From a4fe59e820961215bcc0300cc1b9d58eb8487e86 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Fri, 28 Feb 2025 14:32:58 +0000 Subject: [PATCH 1/2] CppRef changes. These changes were made as part of the prototyping for use of the new arbitrary self types v2 Rust feature (#1429) but are worth promoting into main even before that's landed. Some tweaks: * We no longer depend on the `arbitrary_self_types_pointers` nightly feature but instead just `arbitrary_self_types`. * CppRef no longer has an associated lifetime. Instead there's a separate CppLtRef type. --- Cargo.toml | 2 +- .../codegen_rs/function_wrapper_rs.rs | 11 +- examples/reference-wrappers/src/main.rs | 2 +- integration-tests/tests/cpprefs_test.rs | 4 +- src/lib.rs | 12 +- src/reference_wrapper.rs | 280 +++++++++--------- src/value_param.rs | 2 + 7 files changed, 160 insertions(+), 153 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31840f444..a4c3a7a19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ rust-version = "1.77" resolver = "2" [features] -arbitrary_self_types_pointers = [] +arbitrary_self_types = [] [dependencies] autocxx-macro = { path="macro", version="0.29.0" } diff --git a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs index f73ae0792..ac461bab0 100644 --- a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs +++ b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs @@ -172,9 +172,12 @@ impl TypeConversionPolicy { _ => panic!("Not a pointer"), }; let (ty, wrapper_name) = if is_mut { - (parse_quote! { autocxx::CppMutRef<'a, #ty> }, "CppMutRef") + ( + parse_quote! { autocxx::CppMutLtRef<'a, #ty> }, + "CppMutLtRef", + ) } else { - (parse_quote! { autocxx::CppRef<'a, #ty> }, "CppRef") + (parse_quote! { autocxx::CppLtRef<'a, #ty> }, "CppLtRef") }; let wrapper_name = make_ident(wrapper_name); RustParamConversion::Param { @@ -194,9 +197,9 @@ impl TypeConversionPolicy { _ => panic!("Not a pointer"), }; let ty = if is_mut { - parse_quote! { &mut autocxx::CppMutRef<'a, #ty> } + parse_quote! { autocxx::CppMutRef<#ty> } } else { - parse_quote! { &autocxx::CppRef<'a, #ty> } + parse_quote! { autocxx::CppRef<#ty> } }; RustParamConversion::Param { ty, diff --git a/examples/reference-wrappers/src/main.rs b/examples/reference-wrappers/src/main.rs index 91998fe5c..ca3e0cdc3 100644 --- a/examples/reference-wrappers/src/main.rs +++ b/examples/reference-wrappers/src/main.rs @@ -25,7 +25,7 @@ // Necessary to be able to call methods on reference wrappers. // For that reason, this example only builds on nightly Rust. -#![feature(arbitrary_self_types_pointers)] +#![feature(arbitrary_self_types)] use autocxx::prelude::*; use std::pin::Pin; diff --git a/integration-tests/tests/cpprefs_test.rs b/integration-tests/tests/cpprefs_test.rs index 46349ed7b..902a4c856 100644 --- a/integration-tests/tests/cpprefs_test.rs +++ b/integration-tests/tests/cpprefs_test.rs @@ -27,7 +27,7 @@ fn run_cpprefs_test( generate_pods: &[&str], ) { if !arbitrary_self_types_supported() { - // "unsafe_references_wrapped" requires arbitrary_self_types_pointers, which requires nightly. + // "unsafe_references_wrapped" requires arbitrary_self_types, which requires nightly. return; } do_run_test( @@ -127,7 +127,7 @@ fn test_return_reference_cpprefs() { let rs = quote! { let b = CppPin::new(ffi::Bob { a: 3, b: 4 }); let b_ref = b.as_cpp_ref(); - let bob = ffi::give_bob(&b_ref); + let bob = ffi::give_bob(b_ref); let val = unsafe { bob.as_ref() }; assert_eq!(val.b, 4); }; diff --git a/src/lib.rs b/src/lib.rs index b0eeec17a..eb5623b4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] #![cfg_attr(nightly, feature(unsize))] #![cfg_attr(nightly, feature(dispatch_from_dyn))] +#![cfg_attr(nightly, feature(arbitrary_self_types))] // Copyright 2020 Google LLC // @@ -21,7 +22,9 @@ mod rvalue_param; pub mod subclass; mod value_param; -pub use reference_wrapper::{AsCppMutRef, AsCppRef, CppMutRef, CppPin, CppRef, CppUniquePtrPin}; +pub use reference_wrapper::{ + AsCppMutRef, AsCppRef, CppLtRef, CppMutLtRef, CppMutRef, CppPin, CppRef, CppUniquePtrPin, +}; #[cfg_attr(doc, aquamarine::aquamarine)] /// Include some C++ headers in your Rust project. @@ -270,7 +273,7 @@ macro_rules! concrete { /// them to be wrapped in a `CppRef` type: see [`CppRef`]. /// This only works on nightly Rust because it /// depends upon an unstable feature -/// (`arbitrary_self_types_pointers`). However, it should +/// (`arbitrary_self_types`). However, it should /// eliminate all undefined behavior related to Rust's /// stricter aliasing rules than C++. #[macro_export] @@ -594,10 +597,7 @@ pub trait WithinBox { fn within_box(self) -> Pin>; /// Create this item inside a [`CppPin`]. This is a good option if you /// want to own this option within Rust, but you want to create [`CppRef`] - /// C++ references to it. You'd only want to choose that option if you have - /// enabled the C++ reference wrapper support by using the - /// `safety!(unsafe_references_wrapped`) directive. If you haven't done - /// that, ignore this function. + /// C++ references to it. fn within_cpp_pin(self) -> CppPin; } diff --git a/src/reference_wrapper.rs b/src/reference_wrapper.rs index 3d7d560ce..2baeaaa87 100644 --- a/src/reference_wrapper.rs +++ b/src/reference_wrapper.rs @@ -8,8 +8,9 @@ use core::{marker::PhantomData, ops::Deref, pin::Pin}; +use std::ops::DerefMut; #[cfg(nightly)] -use std::{marker::Unsize, ops::DispatchFromDyn}; +use std::{marker::Unsize, ops::DispatchFromDyn, ops::Receiver}; use cxx::{memory::UniquePtrTarget, UniquePtr}; @@ -36,25 +37,15 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// # Calling methods /// /// As noted, one of the main reasons for this type is to call methods. -/// Unfortunately, that depends on unstable Rust features. If you can't +/// Currently, that depends on unstable Rust features. If you can't /// call methods on one of these references, check you're using nightly -/// and add `#![feature(arbitrary_self_types_pointers)]` to your crate. +/// and add `#![feature(arbitrary_self_types)]` to your crate. /// -/// # Lifetimes and cloneability +/// # Lifetimes /// -/// Although these references implement C++ aliasing semantics, they -/// do attempt to give you Rust lifetime tracking. This means if a C++ object -/// gives you a reference, you won't be able to use that reference after the -/// C++ object is no longer around. -/// -/// This is usually what you need, since a C++ object will typically give -/// you a reference to part of _itself_ or something that it owns. But, -/// if you know that the returned reference lasts longer than its vendor, -/// you can use `lifetime_cast` to get a long-lived version. -/// -/// On the other hand, these references do not give you Rust's exclusivity -/// guarantees. These references can be freely cloned, and using [`CppRef::const_cast`] -/// you can even make a mutable reference from an immutable reference. +/// A `CppRef` is not associated with any Rust lifetime. Normally, for +/// ergonomics, you actually may want a lifetime associated. +/// [`CppLtRef`] gives you this. /// /// # Field access /// @@ -68,14 +59,6 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// store a [`CppPin`] in a struct field, get a `CppRef` to its referent, then /// use a setter to reset that field of the struct.) /// -/// # Deref -/// -/// This type implements [`Deref`] because that's the mechanism that the -/// unstable Rust `arbitrary_self_types` features uses to determine callable -/// methods. However, actually calling `Deref::deref` is not permitted and will -/// result in a compilation failure. If you wish to create a Rust reference -/// from the C++ reference, see [`CppRef::as_ref`]. -/// /// # Nullness /// /// Creation of a null C++ reference is undefined behavior (because such @@ -114,15 +97,12 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// Internally, this is represented as a raw pointer in Rust. See the note above /// about Nullness for why we don't use [`core::ptr::NonNull`]. #[repr(transparent)] -pub struct CppRef<'a, T: ?Sized> { - ptr: *const T, - phantom: PhantomData<&'a T>, -} +pub struct CppRef(*const T); -impl<'a, T: ?Sized> CppRef<'a, T> { +impl CppRef { /// Retrieve the underlying C++ pointer. pub fn as_ptr(&self) -> *const T { - self.ptr + self.0 } /// Get a regular Rust reference out of this C++ reference. @@ -142,10 +122,7 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// Create a C++ reference from a raw pointer. pub fn from_ptr(ptr: *const T) -> Self { - Self { - ptr, - phantom: PhantomData, - } + Self(ptr) } /// Create a mutable version of this reference, roughly equivalent @@ -159,13 +136,56 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// Because we never dereference a `CppRef` in Rust, this cannot create /// undefined behavior _within Rust_ and is therefore not unsafe. It is /// however generally unwise, just as it is in C++. Use sparingly. - pub fn const_cast(&self) -> CppMutRef<'a, T> { - CppMutRef { - ptr: self.ptr as *mut T, - phantom: PhantomData, + pub fn const_cast(&self) -> CppMutRef { + CppMutRef(self.0 as *mut T) + } +} + +#[cfg(nightly)] +impl Receiver for CppRef { + type Target = T; +} + +impl Clone for CppRef { + fn clone(&self) -> Self { + Self(self.0) + } +} + +impl Copy for CppRef {} + +#[cfg(nightly)] +impl, U: ?Sized> DispatchFromDyn> for CppRef {} + +/// A [`CppRef`] with an associated lifetime. This can be used in place of +/// any `CppRef` due to a `Deref` implementation. +#[repr(transparent)] +pub struct CppLtRef<'a, T: ?Sized> { + ptr: CppRef, + phantom: PhantomData<&'a T>, +} + +impl Deref for CppLtRef<'_, T> { + type Target = CppRef; + fn deref(&self) -> &Self::Target { + // Safety: this type is transparent and contains a CppRef as + // its only non-zero field. + unsafe { std::mem::transmute(self) } + } +} + +impl Clone for CppLtRef<'_, T> { + fn clone(&self) -> Self { + Self { + ptr: self.ptr.clone(), + phantom: self.phantom, } } +} +impl Copy for CppLtRef<'_, T> {} + +impl CppLtRef<'_, T> { /// Extend the lifetime of the returned reference beyond normal Rust /// borrow checker rules. /// @@ -177,49 +197,27 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// # Usage /// /// When you're given a C++ reference and you know its referent is valid - /// for a long time, use this method. Store the resulting `PhantomReferent` + /// for a long time, use this method. Store the resulting `CppRef` /// somewhere in Rust with an equivalent lifetime. - /// That object can then vend longer-lived `CppRef`s using - /// [`AsCppRef::as_cpp_ref`]. /// /// # Safety /// /// Because `CppRef`s are never dereferenced in Rust, misuse of this API /// cannot lead to undefined behavior _in Rust_ and is therefore not /// unsafe. Nevertheless this can lead to UB in C++, so use carefully. - pub fn lifetime_cast(&self) -> PhantomReferent { - PhantomReferent(self.ptr) - } -} - -impl Deref for CppRef<'_, T> { - type Target = *const T; - #[inline] - fn deref(&self) -> &Self::Target { - // With `inline_const` we can simplify this to: - // const { panic!("you shouldn't deref CppRef!") } - struct C(T); - impl C { - const V: core::convert::Infallible = panic!( - "You cannot directly obtain a Rust reference from a CppRef. Use CppRef::as_ref." - ); - } - match C::::V {} + pub fn lifetime_cast(&self) -> CppRef { + CppRef(self.ptr.as_ptr()) } -} -impl Clone for CppRef<'_, T> { - fn clone(&self) -> Self { + /// Create a C++ reference from a raw pointer. + pub fn from_ptr(ptr: *const T) -> Self { Self { - ptr: self.ptr, - phantom: self.phantom, + ptr: CppRef::from_ptr(ptr), + phantom: PhantomData, } } } -#[cfg(nightly)] -impl, U: ?Sized> DispatchFromDyn> for CppRef<'_, T> {} - /// A C++ non-const reference. These are different from Rust's `&mut T` in that /// several C++ references can exist to the same underlying data ("aliasing") /// and that's not permitted for regular Rust references. @@ -228,15 +226,12 @@ impl, U: ?Sized> DispatchFromDyn> for CppRef /// /// You can convert this to a [`CppRef`] using the [`std::convert::Into`] trait. #[repr(transparent)] -pub struct CppMutRef<'a, T: ?Sized> { - ptr: *mut T, - phantom: PhantomData<&'a mut T>, -} +pub struct CppMutRef(*mut T); -impl CppMutRef<'_, T> { +impl CppMutRef { /// Retrieve the underlying C++ pointer. pub fn as_mut_ptr(&self) -> *mut T { - self.ptr + self.0 } /// Get a regular Rust mutable reference out of this C++ reference. @@ -256,53 +251,60 @@ impl CppMutRef<'_, T> { /// Create a C++ reference from a raw pointer. pub fn from_ptr(ptr: *mut T) -> Self { - Self { - ptr, - phantom: PhantomData, - } - } - - /// Extend the lifetime of the returned reference beyond normal Rust - /// borrow checker rules. See [`CppRef::lifetime_cast`]. - pub fn lifetime_cast(&mut self) -> PhantomReferentMut { - PhantomReferentMut(self.ptr) + Self(ptr) } } -impl Deref for CppMutRef<'_, T> { - type Target = *const T; +/// We implement `Deref` for `CppMutRef` so that any non-mutable +/// methods can be called on a `CppMutRef` instance. +impl Deref for CppMutRef { + type Target = CppRef; #[inline] fn deref(&self) -> &Self::Target { - // With `inline_const` we can simplify this to: - // const { panic!("you shouldn't deref CppRef!") } - struct C(T); - impl C { - const V: core::convert::Infallible = panic!("You cannot directly obtain a Rust reference from a CppMutRef. Use CppMutRef::as_mut."); - } - match C::::V {} + // Safety: `CppMutRef` and `CppRef` have the same + // layout. + unsafe { std::mem::transmute(self) } } } -impl Clone for CppMutRef<'_, T> { +impl Clone for CppMutRef { fn clone(&self) -> Self { - Self { - ptr: self.ptr, - phantom: self.phantom, - } + Self(self.0) + } +} + +impl Copy for CppMutRef {} + +impl From> for CppRef { + fn from(mutable: CppMutRef) -> Self { + Self(mutable.0) } } -impl<'a, T> From> for CppRef<'a, T> { - fn from(mutable: CppMutRef<'a, T>) -> Self { +#[repr(transparent)] +pub struct CppMutLtRef<'a, T: ?Sized> { + ptr: CppMutRef, + phantom: PhantomData<&'a mut T>, +} + +impl CppMutLtRef<'_, T> { + /// Extend the lifetime of the returned reference beyond normal Rust + /// borrow checker rules. See [`CppLtRef::lifetime_cast`]. + pub fn lifetime_cast(&mut self) -> CppMutRef { + CppMutRef(self.ptr.as_mut_ptr()) + } + + /// Create a C++ reference from a raw pointer. + pub fn from_ptr(ptr: *mut T) -> Self { Self { - ptr: mutable.ptr, + ptr: CppMutRef::from_ptr(ptr), phantom: PhantomData, } } } #[cfg(nightly)] -impl, U: ?Sized> DispatchFromDyn> for CppMutRef<'_, T> {} +impl, U: ?Sized> DispatchFromDyn> for CppMutRef {} /// Any type which can return a C++ reference to its contents. pub trait AsCppRef { @@ -316,9 +318,9 @@ pub trait AsCppMutRef: AsCppRef { fn as_cpp_mut_ref(&mut self) -> CppMutRef; } -impl AsCppRef for CppMutRef<'_, T> { +impl AsCppRef for CppMutRef { fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.ptr) + CppRef::from_ptr(self.0 as *const T) } } @@ -384,7 +386,9 @@ impl CppPinContents { /// /// See also [`CppUniquePtrPin`], which is equivalent for data which is in /// a [`cxx::UniquePtr`]. -pub struct CppPin(Box>); +// We also keep a `CppMutRef` to the contents for the sake of our `Deref` +// implementation. +pub struct CppPin(Box>, CppMutRef); impl CppPin { /// Imprison the Rust data within a `CppPin`. This eliminates any remaining @@ -395,7 +399,9 @@ impl CppPin { where T: Sized, { - Self(Box::new(CppPinContents(item))) + let mut contents = Box::new(CppPinContents(item)); + let ptr = contents.addr_of_mut(); + Self(contents, CppMutRef(ptr)) } /// Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining @@ -412,8 +418,9 @@ impl CppPin { // to // Box> // is safe. - let contents = unsafe { std::mem::transmute::, Box>>(item) }; - Self(contents) + let mut contents = unsafe { std::mem::transmute::, Box>>(item) }; + let ptr = contents.addr_of_mut(); + Self(contents, CppMutRef(ptr)) } // Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining @@ -493,6 +500,20 @@ impl AsCppMutRef for CppPin { } } +impl Deref for CppPin { + type Target = CppMutRef; + + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl DerefMut for CppPin { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.1 + } +} + /// Any newtype wrapper which causes the contained [`UniquePtr`] target to obey C++ reference /// semantics rather than Rust reference semantics. That is, multiple aliasing /// mutable C++ references may exist to the contents. @@ -500,14 +521,15 @@ impl AsCppMutRef for CppPin { /// C++ references are permitted to alias one another, and commonly do. /// Rust references must alias according only to the narrow rules of the /// borrow checker. -pub struct CppUniquePtrPin(UniquePtr); +pub struct CppUniquePtrPin(UniquePtr, CppMutRef); impl CppUniquePtrPin { /// Imprison the type within a `CppPin`. This eliminates any remaining /// Rust references (since we take the item by value) and this object /// subsequently only vends C++ style references, not Rust references. pub fn new(item: UniquePtr) -> Self { - Self(item) + let ptr = item.as_mut_ptr(); + Self(item, CppMutRef::from_ptr(ptr)) } /// Get an immutable pointer to the underlying object. @@ -527,46 +549,26 @@ impl AsCppRef for CppUniquePtrPin { impl AsCppMutRef for CppUniquePtrPin { fn as_cpp_mut_ref(&mut self) -> CppMutRef { - let pinnned_ref: Pin<&mut T> = self - .0 - .as_mut() - .expect("UniquePtr was null; we can't make a C++ reference"); - let ptr = unsafe { Pin::into_inner_unchecked(pinnned_ref) }; - CppMutRef::from_ptr(ptr) + self.1.clone() } } -/// A structure used to extend the lifetime of a returned C++ reference, -/// to indicate to Rust that it's beyond the normal Rust lifetime rules. -/// See [`CppRef::lifetime_cast`]. -#[repr(transparent)] -pub struct PhantomReferent(*const T); +impl Deref for CppUniquePtrPin { + type Target = CppMutRef; -impl AsCppRef for PhantomReferent { - fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.0) + fn deref(&self) -> &Self::Target { + &self.1 } } -/// A structure used to extend the lifetime of a returned C++ mutable reference, -/// to indicate to Rust that it's beyond the normal Rust lifetime rules. -/// See [`CppRef::lifetime_cast`]. -#[repr(transparent)] -pub struct PhantomReferentMut(*mut T); - -impl AsCppRef for PhantomReferentMut { +// It would be very nice to be able to impl Deref for UniquePtr +impl AsCppRef for cxx::UniquePtr { fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.0) - } -} - -impl AsCppMutRef for PhantomReferentMut { - fn as_cpp_mut_ref(&mut self) -> CppMutRef { - CppMutRef::from_ptr(self.0) + CppRef::from_ptr(self.as_ptr()) } } -#[cfg(all(feature = "arbitrary_self_types_pointers", test))] +#[cfg(all(feature = "arbitrary_self_types", test))] mod tests { use super::*; diff --git a/src/value_param.rs b/src/value_param.rs index 7386d19fb..bb837f11c 100644 --- a/src/value_param.rs +++ b/src/value_param.rs @@ -109,6 +109,8 @@ where } } +// TODO implement for CppPin and for CppRef + unsafe impl ValueParam for UniquePtr where T: UniquePtrTarget, From 389c868c962ee4e12d113a547d79c8d1055a6c59 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 16 Jan 2025 08:09:35 +0000 Subject: [PATCH 2/2] Partial conversion to CppRef everywhere Background: Rust references have certain rules, most notably that the underlying data cannot be changed while an immutable reference exists. That's essentially impossible to promise for any C++ data; C++ may retain references or pointers to data any modify it at any time. This presents a problem for Rust/C++ interop tooling. Various solutions or workarounds are possible: 1) All C++ data is represented as zero-sized types. This is the approach taken by cxx for opaque types. This sidesteps all of the Rust reference rules, since those rules only apply to areas of memory that are referred to. This doesn't really work well enough for autocxx since we want to be able to keep C++ data on the Rust stack, using all the fancy moveit shenanigans, and that means that Rust must know the true size and alignment of the type. 2) All C++ data is represented as UnsafeCell>. This also sidesteps the reference rules. This would be a valid option for autocxx. 3) Have a sufficiently simple language boundary that humans can reasonably guarantee there are no outstanding references on the C++ side which could be used to modify the underlying data. This is the approach taken by cxx for cxx::kind::Trivial types. It's just about possible to cause UB using one of these types, but you really have to work at it. In practice such UB is unlikely. 4) Never allow Rust references to C++ types. Instead use a special smart pointer type in Rust, representing a C++ reference. This is the direction in this PR. More detail on this last approach here: https://medium.com/@adetaylor/are-we-reference-yet-c-references-in-rust-72c1c6c7015a This facility is already in autocxx, by adopting the safety policy "unsafe_references_wrapped". However, it hasn't really been battle tested and has a bunch of deficiencies. It's been awaiting formal Rust support for "arbitrary self types" so that methods can be called on such smart pointers. This is now [fairly close to stabilization](https://github.com/rust-lang/rust/issues/44874#issuecomment-2564299131); this PR is part of the experimentation required to investigate whether that rustc feature should go ahead and get stabilized. This PR essentially converts autocxx to only operate in this mode - there should no longer ever be Rust references to C++ data. This PR is incomplete: * There are still 60 failing integration tests. Mostly these relate to subclass support, which isn't yet converted. * `ValueParam` and `RValueParam` need to support taking `CppPin`, and possibly `CppRef` etc. * Because we can't implement `Deref` for `cxx::UniquePtr` to emit a `CppRef`, unfortunately `cxx::UniquePtr` can't be used in cases where we want to provide a `const T&`. It's necessary to call `.as_cpp_ref()` on the `UniquePtr`. This is sufficiently annoying that it might be necessary to implement a trait `ReferenceParam` like we have for `ValueParam` and `RValueParam`. (Alternatives include upstreaming `CppRef` into cxx, but per reason 4 listed above, the complexity probably isn't merited for statically-declared cxx interfaces; or separating from cxx entirely.) This also shows up a [Rustc problem which is fixed here](https://github.com/rust-lang/rust/pull/135179). Ergonomic findings: * The problem with `cxx::UniquePtr` as noted above. * It's nice that `Deref` coercion allows methods to be called on `CppPin` as well as `CppRef`. * To get the same benefit for parameters being passed in by reference, you need to pass in `&my_cpp_pin_wrapped_thing` which is weird given that the whole point is we're trying to avoid Rust references. Obviously, calling `.as_cpp_ref()` works too, so this weirdness can be avoided. * When creating some C++ data `T`, in Rust, it's annoying to have to decide a-priori whether it'll be Rust or C++ accessing the data. If the former, you just create a new `T`; if the latter you need to wrap it in `CppPin::new`. This is only really a problem when creating a C++ object on which you'll call methods. It feels like it'll be OK in practice. Possibly this can be resolved by making the method receiver some sort of `impl MethodReceiver` generic; an implementation for `T` could be provided which auto-wraps it into a `CppPin` (consuming it at that point). This sounds messy though. A bit more thought required, but even if this isn't possible it doesn't sound like a really serious ergonomics problem, especially if we can use `#[diagnostic::on_unimplemented]` somehow to guide. Next steps here: * Stabilize arbitrary self types. This PR has gone far enough to show that there are no really serious unexpected issues there. * Implement `ValueParam` and `RValueParam` as necessary for `CppRef` and `CppPin` types. * Work on those ergonomic issues to the extent possible. * Make a bold decision about whether autocxx should shift wholesale away from `&` to `CppRef`. If so, this will be a significant breaking change. --- demo/src/main.rs | 8 +- engine/src/conversion/analysis/fun/mod.rs | 10 +- engine/src/conversion/codegen_rs/mod.rs | 12 +- engine/src/conversion/conversion_tests.rs | 2 +- engine/src/conversion/mod.rs | 1 - integration-tests/src/lib.rs | 1 + integration-tests/tests/integration_test.rs | 315 +++++++++++--------- parser/src/config.rs | 13 +- src/reference_wrapper.rs | 4 - 9 files changed, 190 insertions(+), 176 deletions(-) diff --git a/demo/src/main.rs b/demo/src/main.rs index 798f93245..81edf4922 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -6,6 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(arbitrary_self_types)] + use autocxx::prelude::*; include_cpp! { #include "input.h" @@ -16,9 +18,9 @@ include_cpp! { fn main() { println!("Hello, world! - C++ math should say 12={}", ffi::DoMath(4)); - let mut goat = ffi::Goat::new().within_box(); - goat.as_mut().add_a_horn(); - goat.as_mut().add_a_horn(); + let goat = ffi::Goat::new().within_cpp_pin(); + goat.add_a_horn(); + goat.add_a_horn(); assert_eq!( goat.describe().as_ref().unwrap().to_string_lossy(), "This goat has 2 horns." diff --git a/engine/src/conversion/analysis/fun/mod.rs b/engine/src/conversion/analysis/fun/mod.rs index 6ad07ef2c..d93b25f66 100644 --- a/engine/src/conversion/analysis/fun/mod.rs +++ b/engine/src/conversion/analysis/fun/mod.rs @@ -1541,13 +1541,15 @@ impl<'a> FnAnalyzer<'a> { let from_type = self_ty.as_ref().unwrap(); let from_type_path = from_type.to_type_path(); let to_type = to_type.to_type_path(); - let (trait_signature, ty, method_name) = match *mutable { + let (trait_signature, ty, method_name): (_, Type, _) = match *mutable { CastMutability::ConstToConst => ( parse_quote! { - AsRef < #to_type > + autocxx::AsCppRef < #to_type > }, - Type::Path(from_type_path), - "as_ref", + parse_quote! { + autocxx::CppRef< #from_type_path > + }, + "as_cpp_ref", ), CastMutability::MutToConst => ( parse_quote! { diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs index b6f6d2961..145fb4f5f 100644 --- a/engine/src/conversion/codegen_rs/mod.rs +++ b/engine/src/conversion/codegen_rs/mod.rs @@ -18,7 +18,7 @@ mod utils; use indexmap::map::IndexMap as HashMap; use indexmap::set::IndexSet as HashSet; -use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun, UnsafePolicy}; +use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun}; use itertools::Itertools; use proc_macro2::{Span, TokenStream}; @@ -121,7 +121,6 @@ fn get_string_items() -> Vec { /// 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, @@ -133,14 +132,12 @@ impl<'a> RsCodeGenerator<'a> { /// Generate code for a set of APIs that was discovered during parsing. pub(crate) fn generate_rs_code( all_apis: ApiVec, - unsafe_policy: &'a UnsafePolicy, include_list: &'a [String], bindgen_mod: ItemMod, config: &'a IncludeCppConfig, header_name: Option, ) -> Vec { let c = Self { - unsafe_policy, include_list, bindgen_mod, original_name_map: CppNameMap::new_from_apis(&all_apis), @@ -515,11 +512,8 @@ impl<'a> RsCodeGenerator<'a> { name, superclass, .. } => { let methods = associated_methods.get(&superclass); - 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); + let generate_peer_constructor = + subclasses_with_a_single_trivial_constructor.contains(&name.0.name); self.generate_subclass(name, &superclass, methods, generate_peer_constructor) } Api::ExternCppType { diff --git a/engine/src/conversion/conversion_tests.rs b/engine/src/conversion/conversion_tests.rs index ae8c8e187..e32b2ec69 100644 --- a/engine/src/conversion/conversion_tests.rs +++ b/engine/src/conversion/conversion_tests.rs @@ -33,7 +33,7 @@ fn do_test(input: ItemMod) { bc.convert( input, parse_callback_results, - UnsafePolicy::AllFunctionsSafe, + UnsafePolicy::ReferencesWrappedAllFunctionsSafe, inclusions, &CodegenOptions::default(), "", diff --git a/engine/src/conversion/mod.rs b/engine/src/conversion/mod.rs index 0012fadc7..e72ed0011 100644 --- a/engine/src/conversion/mod.rs +++ b/engine/src/conversion/mod.rs @@ -196,7 +196,6 @@ impl<'a> BridgeConverter<'a> { .map_err(ConvertError::Cpp)?; let rs = RsCodeGenerator::generate_rs_code( analyzed_apis, - &unsafe_policy, self.include_list, bindgen_mod, self.config, diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index 408123ec3..9e2ed5f1d 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -380,6 +380,7 @@ pub fn do_run_test( let safety_policy = format_ident!("{}", safety_policy); let unexpanded_rust = quote! { #module_attributes + #![feature(arbitrary_self_types)] use autocxx::prelude::*; diff --git a/integration-tests/tests/integration_test.rs b/integration-tests/tests/integration_test.rs index 1fb9b0757..d53a0b28a 100644 --- a/integration-tests/tests/integration_test.rs +++ b/integration-tests/tests/integration_test.rs @@ -129,6 +129,7 @@ fn test_nested_module() { "}; let hexathorpe = Token![#](Span::call_site()); let unexpanded_rust = quote! { + #![feature(arbitrary_self_types)] mod a { use autocxx::prelude::*; @@ -203,7 +204,7 @@ fn test_give_up_int() { std::unique_ptr give_up(); "}; let rs = quote! { - assert_eq!(ffi::give_up().as_ref().unwrap(), 12); + assert_eq!(ffi::give_up().as_cpp_ref(), 12); }; run_test(cxx, hdr, rs, &["give_up"], &[]); } @@ -221,7 +222,7 @@ fn test_give_up_ctype() { std::unique_ptr give_up(); "}; let rs = quote! { - assert_eq!(ffi::give_up().as_ref().unwrap(), autocxx::c_int(12)); + assert_eq!(ffi::give_up().as_cpp_ref(), autocxx::c_int(12)); }; run_test(cxx, hdr, rs, &["give_up"], &[]); } @@ -239,7 +240,7 @@ fn test_give_string_up() { std::unique_ptr give_str_up(); "}; let rs = quote! { - assert_eq!(ffi::give_str_up().as_ref().unwrap().to_str().unwrap(), "Bob"); + assert_eq!(ffi::give_str_up().to_str().unwrap(), "Bob"); }; run_test(cxx, hdr, rs, &["give_str_up"], &[]); } @@ -328,7 +329,7 @@ fn test_cycle_string_by_ref() { "}; let rs = quote! { let s = ffi::give_str(); - assert_eq!(ffi::take_str(s.as_ref().unwrap()), 3); + assert_eq!(ffi::take_str(s.as_cpp_ref()), 3); }; let generate = &["give_str", "take_str"]; run_test(cxx, hdr, rs, generate, &[]); @@ -472,7 +473,7 @@ fn test_negative_take_as_pod_with_destructor() { uint32_t take_bob(Bob a); "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(ffi::take_bob(a), 12); }; run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]); @@ -496,7 +497,7 @@ fn test_negative_take_as_pod_with_move_constructor() { uint32_t take_bob(Bob a); "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(ffi::take_bob(a), 12); }; run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]); @@ -524,7 +525,7 @@ fn test_take_as_pod_with_is_relocatable() { uint32_t take_bob(Bob a); "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(ffi::take_bob(a), 12); }; run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]); @@ -546,8 +547,8 @@ fn test_take_pod_by_ref() { uint32_t take_bob(const Bob& a); "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; - assert_eq!(ffi::take_bob(&a), 12); + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); + assert_eq!(ffi::take_bob(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]); } @@ -572,8 +573,8 @@ fn test_take_pod_by_ref_and_ptr() { uint32_t take_bob_ptr(const Bob* a); "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; - assert_eq!(ffi::take_bob_ref(&a), 12); + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); + assert_eq!(ffi::take_bob_ref(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &["take_bob_ref", "take_bob_ptr"], &["Bob"]); } @@ -596,9 +597,9 @@ fn test_return_pod_by_ref_and_ptr() { } "}; let rs = quote! { - let a = ffi::A { b: ffi::B { a: 3 } }; - assert_eq!(ffi::return_b_ref(&a).a, 3); - let b_ptr = ffi::return_b_ptr(&a); + let a = CppPin::new(ffi::A { b: ffi::B { a: 3 } }); + assert_eq!(unsafe { ffi::return_b_ref(a.as_cpp_ref()).as_ref()}.a, 3); + let b_ptr = ffi::return_b_ptr(a.as_cpp_ref()); assert_eq!(unsafe { b_ptr.as_ref() }.unwrap().a, 3); }; run_test("", hdr, rs, &["return_b_ref", "return_b_ptr"], &["A", "B"]); @@ -705,7 +706,7 @@ fn test_take_nonpod_by_ref() { "}; let rs = quote! { let a = ffi::make_bob(12); - assert_eq!(ffi::take_bob(&a), 12); + assert_eq!(ffi::take_bob(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]); } @@ -796,9 +797,9 @@ fn test_take_nonpod_by_ptr_in_method() { "}; let rs = quote! { let a = ffi::A::new().within_unique_ptr(); - let b = a.as_ref().unwrap().make_bob(12); + let b = a.as_cpp_ref().make_bob(12); let b_ptr = b.into_raw(); - assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr) }, 12); + assert_eq!(unsafe { a.as_cpp_ref().take_bob(b_ptr) }, 12); unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop }; run_test("", hdr, rs, &["A", "Bob"], &[]); @@ -834,9 +835,9 @@ fn test_take_nonpod_by_ptr_in_wrapped_method() { let rs = quote! { let a = ffi::A::new().within_unique_ptr(); let c = ffi::C::new().within_unique_ptr(); - let b = a.as_ref().unwrap().make_bob(12); + let b = a.as_cpp_ref().make_bob(12); let b_ptr = b.into_raw(); - assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr, c) }, 12); + assert_eq!(unsafe { a.as_cpp_ref().take_bob(b_ptr, c) }, 12); unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop }; run_test("", hdr, rs, &["A", "Bob", "C"], &[]); @@ -868,9 +869,9 @@ fn run_char_test(builder_modifier: Option) { let a = ffi::A::new().within_unique_ptr(); let c1 = ffi::C::new().within_unique_ptr(); let c2 = ffi::C::new().within_unique_ptr(); - let ch = a.as_ref().unwrap().make_char(c1); + let ch = a.as_cpp_ref().make_char(c1); assert_eq!(unsafe { ch.as_ref()}.unwrap(), &104i8); - assert_eq!(unsafe { a.as_ref().unwrap().take_char(ch, c2) }, 104); + assert_eq!(unsafe { a.as_cpp_ref().take_char(ch, c2) }, 104); }; run_test_ex( "", @@ -916,7 +917,7 @@ fn test_take_nonpod_by_mut_ref() { "}; let rs = quote! { let mut a = ffi::make_bob(12); - assert_eq!(ffi::take_bob(a.pin_mut()), 12); + assert_eq!(ffi::take_bob(a.as_cpp_ref().const_cast()), 12); }; // TODO confirm that the object really was mutated by C++ in this // and similar tests. @@ -1015,7 +1016,7 @@ fn test_cycle_nonpod_with_str_by_ref() { "}; let rs = quote! { let a = ffi::make_bob(); - assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 32); + assert_eq!(ffi::take_bob(a.as_cpp_ref()), 32); }; run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]); } @@ -1040,7 +1041,7 @@ fn test_make_up() { "}; let rs = quote! { let a = ffi::Bob::new().within_unique_ptr(); // TODO test with all sorts of arguments. - assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 3); + assert_eq!(ffi::take_bob(a.as_cpp_ref()), 3); }; run_test(cxx, hdr, rs, &["Bob", "take_bob"], &[]); } @@ -1064,8 +1065,8 @@ fn test_make_up_with_args() { uint32_t take_bob(const Bob& a); "}; let rs = quote! { - let a = ffi::Bob::new(12, 13).within_unique_ptr(); - assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 12); + let a = ffi::Bob::new(12, 13).within_cpp_pin(); + assert_eq!(ffi::take_bob(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]); } @@ -1087,7 +1088,7 @@ fn test_make_up_int() { "}; let rs = quote! { let a = ffi::Bob::new(3).within_unique_ptr(); - assert_eq!(a.as_ref().unwrap().b, 3); + assert_eq!(a.as_cpp_ref().b, 3); }; run_test(cxx, hdr, rs, &["Bob"], &[]); } @@ -1227,7 +1228,7 @@ fn test_pod_method() { }; "}; let rs = quote! { - let a = ffi::Bob { a: 12, b: 13 }; + let a = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(a.get_bob(), 12); }; run_test(cxx, hdr, rs, &[], &["Bob"]); @@ -1405,7 +1406,7 @@ fn test_method_pass_pod_by_value() { "}; let rs = quote! { let a = ffi::Anna { a: 14 }; - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a), 12); }; run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]); @@ -1470,7 +1471,7 @@ fn test_inline_method() { "}; let rs = quote! { let a = ffi::Anna { a: 14 }; - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a), 12); }; run_test("", hdr, rs, &[], &["Bob", "Anna"]); @@ -1496,9 +1497,9 @@ fn test_method_pass_pod_by_reference() { }; "}; let rs = quote! { - let a = ffi::Anna { a: 14 }; - let b = ffi::Bob { a: 12, b: 13 }; - assert_eq!(b.get_bob(&a), 12); + let a = CppPin::new(ffi::Anna { a: 14 }); + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); + assert_eq!(b.get_bob(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]); } @@ -1524,7 +1525,7 @@ fn test_method_pass_pod_by_mut_reference() { "}; let rs = quote! { let mut a = Box::pin(ffi::Anna { a: 14 }); - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a.as_mut()), 12); }; run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]); @@ -1552,7 +1553,7 @@ fn test_method_pass_pod_by_up() { "}; let rs = quote! { let a = ffi::Anna { a: 14 }; - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(cxx::UniquePtr::new(a)), 12); }; run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]); @@ -1587,7 +1588,7 @@ fn test_method_pass_nonpod_by_value() { "}; let rs = quote! { let a = ffi::give_anna().within_box(); - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a), 12); }; run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]); @@ -1696,7 +1697,7 @@ fn test_method_pass_nonpod_by_value_with_up() { let rs = quote! { let a = ffi::give_anna().within_unique_ptr(); let a2 = ffi::give_anna().within_unique_ptr(); - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a, a2), 12); }; run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]); @@ -1763,8 +1764,8 @@ fn test_method_pass_nonpod_by_reference() { "}; let rs = quote! { let a = ffi::give_anna().within_box(); - let b = ffi::Bob { a: 12, b: 13 }; - assert_eq!(b.get_bob(a.as_ref().get_ref()), 12); + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); + assert_eq!(b.get_bob(a.as_cpp_ref()), 12); }; run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]); } @@ -1798,8 +1799,8 @@ fn test_method_pass_nonpod_by_mut_reference() { "}; let rs = quote! { let mut a = ffi::give_anna().within_unique_ptr(); - let b = ffi::Bob { a: 12, b: 13 }; - assert_eq!(b.get_bob(a.as_mut().unwrap()), 12); + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); + assert_eq!(b.get_bob(a.as_cpp_ref().const_cast()), 12); }; run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]); } @@ -1834,7 +1835,7 @@ fn test_method_pass_nonpod_by_up() { "}; let rs = quote! { let a = ffi::give_anna().within_unique_ptr(); - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); assert_eq!(b.get_bob(a), 12); }; run_test(cxx, hdr, rs, &["give_anna"], &["Bob"]); @@ -1864,7 +1865,7 @@ fn test_method_return_nonpod_by_value() { }; "}; let rs = quote! { - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); let a = b.get_anna().within_unique_ptr(); assert!(!a.is_null()); }; @@ -1909,7 +1910,7 @@ fn test_return_string_by_value() { "}; let rs = quote! { let a = ffi::get_msg(); - assert!(a.as_ref().unwrap() == "hello"); + assert!(a.as_cpp_ref() == "hello"); }; run_test(cxx, hdr, rs, &["get_msg"], &[]); } @@ -1939,7 +1940,7 @@ fn test_method_pass_string_by_value() { "}; let rs = quote! { let a = ffi::get_msg(); - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); let c = b.measure_string(a); assert_eq!(c, 5); }; @@ -1964,7 +1965,7 @@ fn test_method_return_string_by_value() { }; "}; let rs = quote! { - let b = ffi::Bob { a: 12, b: 13 }; + let b = CppPin::new(ffi::Bob { a: 12, b: 13 }); let a = b.get_msg(); assert!(a.as_ref().unwrap() == "hello"); }; @@ -2103,13 +2104,13 @@ fn test_multiple_classes_with_methods() { let mut os= make_opaque_struct().within_unique_ptr(); assert_eq!(os.get(), 2); - assert_eq!(os.pin_mut().inc(), 3); - assert_eq!(os.pin_mut().inc(), 4); + assert_eq!(os.as_cpp_mut_ref().inc(), 3); + assert_eq!(os.as_cpp_mut_ref().inc(), 4); let mut oc = make_opaque_class().within_unique_ptr(); assert_eq!(oc.get(), 3); - assert_eq!(oc.pin_mut().inc(), 4); - assert_eq!(oc.pin_mut().inc(), 5); + assert_eq!(oc.as_cpp_mut_ref().inc(), 4); + assert_eq!(oc.as_cpp_mut_ref().inc(), 5); }; run_test( cxx, @@ -2356,7 +2357,7 @@ fn test_overload_methods() { "}; let rs = quote! { use ffi::ToCppString; - let a = ffi::Bob { a: 12 }; + let a = CppPin::new(ffi::Bob { a: 12 }); a.daft(32); a.daft1(8); a.daft2("hello".into_cpp()); @@ -2497,8 +2498,8 @@ fn test_return_reference() { const Bob& give_bob(const Bob& input_bob); "}; let rs = quote! { - let b = ffi::Bob { a: 3, b: 4 }; - assert_eq!(ffi::give_bob(&b).b, 4); + let b = CppPin::new(ffi::Bob { a: 3, b: 4 }); + assert_eq!(ffi::give_bob(b.as_cpp_ref()).b, 4); }; run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]); } @@ -2559,7 +2560,7 @@ fn test_member_return_reference() { "}; let rs = quote! { let mut b = ffi::A::new().within_unique_ptr(); - b.pin_mut().get_str(); + b.as_cpp_ref().const_cast().get_str(); }; run_test("", hdr, rs, &["A"], &[]); } @@ -2616,6 +2617,7 @@ fn test_destructor_no_safety() { "}; let hexathorpe = Token![#](Span::call_site()); let unexpanded_rust = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; include_cpp!( @@ -2771,7 +2773,7 @@ fn test_give_nonpod_typedef_by_value() { inline uint32_t take_horace(const Horace& horace) { return horace.b; } "}; let rs = quote! { - assert_eq!(ffi::take_horace(&moveit!(ffi::give_bob())), 4); + assert_eq!(ffi::take_horace(moveit!(ffi::give_bob())), 4); }; run_test(cxx, hdr, rs, &["give_bob", "take_horace"], &[]); } @@ -2848,8 +2850,8 @@ fn test_conflicting_methods() { }; "}; let rs = quote! { - let a = ffi::Bob { a: 10 }; - let b = ffi::Fred { b: 20 }; + let a = CppPin::new(ffi::Bob { a: 10 }); + let b = CppPin::new(ffi::Fred { b: 20 }); assert_eq!(a.get(), 10); assert_eq!(b.get(), 20); }; @@ -2889,8 +2891,8 @@ fn test_conflicting_up_wrapper_methods_not_in_ns() { let rs = quote! { let a = ffi::Bob::new().within_unique_ptr(); let b = ffi::Fred::new().within_unique_ptr(); - assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello"); - assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye"); + assert_eq!(a.as_cpp_ref().get().to_str().unwrap(), "hello"); + assert_eq!(b.as_cpp_ref().get().to_str().unwrap(), "goodbye"); }; run_test(cxx, hdr, rs, &["Bob", "Fred"], &[]); } @@ -2917,8 +2919,8 @@ fn test_conflicting_methods_in_ns() { } "}; let rs = quote! { - let a = ffi::A::Bob { a: 10 }; - let b = ffi::B::Fred { b: 20 }; + let a = CppPin::new(ffi::A::Bob { a: 10 }); + let b = CppPin::new(ffi::B::Fred { b: 20 }); assert_eq!(a.get(), 10); assert_eq!(b.get(), 20); }; @@ -2954,8 +2956,8 @@ fn test_conflicting_up_wrapper_methods_in_ns() { let rs = quote! { let a = ffi::A::Bob::new().within_unique_ptr(); let b = ffi::B::Fred::new().within_unique_ptr(); - assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello"); - assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye"); + assert_eq!(a.as_cpp_ref().get().to_str().unwrap(), "hello"); + assert_eq!(b.as_cpp_ref().get().to_str().unwrap(), "goodbye"); }; run_test(cxx, hdr, rs, &["A::Bob", "B::Fred"], &[]); } @@ -3075,7 +3077,8 @@ fn test_string_let_cxx_string() { "}; let rs = quote! { autocxx::cxx::let_cxx_string!(s = "hello"); - ffi::take_string(&s); + let s = CppRef::from_ptr(&s); + ffi::take_string(s); }; run_test("", hdr, rs, &["take_string"], &[]); } @@ -3167,7 +3170,7 @@ fn test_non_pod_constant() { let a = ffi::BOB; // following line assumes that 'a' is a &Bob // but who knows how we'll really do this. - assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello"); + assert_eq!(a.get().as_cpp_ref().to_str().unwrap(), "hello"); }; run_test("", hdr, rs, &["BOB"], &[]); } @@ -3397,8 +3400,8 @@ fn test_associated_type_templated_typedef() { inline void take_string_piece(const StringPiece&) {} "}; let rs = quote! { - let sp = ffi::Container::new().within_box(); - ffi::take_string_piece(sp.get_string_piece()); + let sp = ffi::Container::new().within_cpp_pin(); + ffi::take_string_piece(&sp.get_string_piece()); }; run_test("", hdr, rs, &["take_string_piece", "Container"], &[]); } @@ -3489,8 +3492,8 @@ fn test_associated_type_templated_typedef_by_value_forward_declaration() { // As this template is forward declared we shouldn't be able to pass it by // value, but we still want to be able to use it by reference. let rs = quote! { - let cont = ffi::Container::new().within_box(); - ffi::take_string_piece_by_ref(cont.as_ref().get_string_piece()); + let cont = ffi::Container::new().within_cpp_pin(); + ffi::take_string_piece_by_ref(&cont.get_string_piece()); }; run_test( cpp, @@ -3624,7 +3627,7 @@ fn test_foreign_ns_meth_arg_pod() { "}; let rs = quote! { let a = ffi::A::Bob { a: 12 }; - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft(a), 12); }; run_test("", hdr, rs, &[], &["A::Bob", "B::C"]); @@ -3650,7 +3653,7 @@ fn test_foreign_ns_meth_arg_nonpod() { "}; let rs = quote! { let a = ffi::A::Bob::new(12).within_unique_ptr(); - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft(a), 12); }; run_test("", hdr, rs, &["A::Bob"], &["B::C"]); @@ -3674,8 +3677,8 @@ fn test_foreign_ns_cons_arg_pod() { } "}; let rs = quote! { - let a = ffi::A::Bob { a: 12 }; - let b = ffi::B::C::new(&a).within_unique_ptr(); + let a = CppPin::new(ffi::A::Bob { a: 12 }); + let b = ffi::B::C::new(a.as_cpp_ref()).within_unique_ptr(); assert_eq!(b.as_ref().unwrap().a, 12); }; run_test("", hdr, rs, &[], &["B::C", "A::Bob"]); @@ -3701,8 +3704,8 @@ fn test_foreign_ns_cons_arg_nonpod() { "}; let rs = quote! { let a = ffi::A::Bob::new(12).within_unique_ptr(); - let b = ffi::B::C::new(&a).within_unique_ptr(); - assert_eq!(b.as_ref().unwrap().a, 12); + let b = ffi::B::C::new(a.as_cpp_ref()).within_unique_ptr(); + assert_eq!(unsafe { b.as_cpp_ref().as_ref().a }, 12); }; run_test("", hdr, rs, &["A::Bob"], &["B::C"]); } @@ -3765,7 +3768,7 @@ fn test_foreign_ns_meth_ret_pod() { } "}; let rs = quote! { - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft().a, 12); }; run_test("", hdr, rs, &[], &["A::Bob", "B::C"]); @@ -3789,8 +3792,8 @@ fn test_foreign_ns_meth_ret_nonpod() { } "}; let rs = quote! { - let b = ffi::B::C { a: 14 }; - b.daft().within_unique_ptr().as_ref().unwrap(); + let b = CppPin::new(ffi::B::C { a: 14 }); + b.daft().within_unique_ptr().as_cpp_ref(); }; run_test("", hdr, rs, &["A::Bob"], &["B::C"]); } @@ -3851,7 +3854,7 @@ fn test_root_ns_meth_arg_pod() { "}; let rs = quote! { let a = ffi::Bob { a: 12 }; - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft(a), 12); }; run_test("", hdr, rs, &[], &["Bob", "B::C"]); @@ -3875,7 +3878,7 @@ fn test_root_ns_meth_arg_nonpod() { "}; let rs = quote! { let a = ffi::Bob::new(12).within_unique_ptr(); - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft(a), 12); }; run_test("", hdr, rs, &["Bob"], &["B::C"]); @@ -3897,9 +3900,9 @@ fn test_root_ns_cons_arg_pod() { } "}; let rs = quote! { - let a = ffi::Bob { a: 12 }; - let b = ffi::B::C::new(&a).within_unique_ptr(); - assert_eq!(b.as_ref().unwrap().a, 12); + let a = CppPin::new(ffi::Bob { a: 12 }); + let b = ffi::B::C::new(a.as_cpp_ref()).within_unique_ptr(); + assert_eq!(b.as_ref().a, 12); }; run_test("", hdr, rs, &[], &["B::C", "Bob"]); } @@ -3922,7 +3925,7 @@ fn test_root_ns_cons_arg_nonpod() { "}; let rs = quote! { let a = ffi::Bob::new(12).within_unique_ptr(); - let b = ffi::B::C::new(&a).within_unique_ptr(); + let b = ffi::B::C::new(a.as_cpp_ref()).within_unique_ptr(); assert_eq!(b.as_ref().unwrap().a, 12); }; run_test("", hdr, rs, &["Bob"], &["B::C"]); @@ -3959,7 +3962,7 @@ fn test_root_ns_func_ret_nonpod() { } "}; let rs = quote! { - ffi::B::daft().within_unique_ptr().as_ref().unwrap(); + ffi::B::daft().within_unique_ptr().as_cpp_ref(); }; run_test("", hdr, rs, &["B::daft", "Bob"], &[]); } @@ -3980,7 +3983,7 @@ fn test_root_ns_meth_ret_pod() { } "}; let rs = quote! { - let b = ffi::B::C { a: 12 }; + let b = CppPin::new(ffi::B::C { a: 12 }); assert_eq!(b.daft().a, 12); }; run_test("", hdr, rs, &[], &["Bob", "B::C"]); @@ -4002,8 +4005,8 @@ fn test_root_ns_meth_ret_nonpod() { } "}; let rs = quote! { - let b = ffi::B::C { a: 12 }; - b.daft().within_unique_ptr().as_ref().unwrap(); + let b = CppPin::new(ffi::B::C { a: 12 }); + b.daft().within_unique_ptr().as_cpp_ref(); }; run_test("", hdr, rs, &["Bob"], &["B::C"]); } @@ -4052,7 +4055,8 @@ fn test_forward_declaration() { let rs = quote! { let b = ffi::B::new().within_unique_ptr(); let a = ffi::get_a(); - b.daft(unsafe { a.as_ref().unwrap() }); + let a_ref = CppRef::from_ptr(ffi::get_a()); + b.as_cpp_ref().daft(a_ref); unsafe { ffi::delete_a(a) }; }; run_test(cpp, hdr, rs, &["B", "get_a", "delete_a"], &[]); @@ -4106,7 +4110,7 @@ fn test_ulong_method() { "}; let rs = quote! { let a = ffi::A::new().within_unique_ptr(); - assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34)), autocxx::c_ulong(34)); + assert_eq!(a.as_cpp_ref().daft(autocxx::c_ulong(34)), autocxx::c_ulong(34)); }; run_test("", hdr, rs, &["A"], &[]); } @@ -4128,7 +4132,7 @@ fn test_ulong_wrapped_method() { let rs = quote! { let b = ffi::B::new().within_unique_ptr(); let a = ffi::A::new().within_unique_ptr(); - assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34), b), autocxx::c_ulong(34)); + assert_eq!(a.as_cpp_ref().daft(autocxx::c_ulong(34), b), autocxx::c_ulong(34)); }; run_test("", hdr, rs, &["A", "B"], &[]); } @@ -4172,7 +4176,7 @@ fn test_nested_type() { let rs = quote! { let _ = ffi::A::new().within_unique_ptr(); let b = ffi::B::new().within_unique_ptr(); - b.as_ref().unwrap().method_on_top_level_type(); + b.as_cpp_ref().method_on_top_level_type(); }; run_test("", hdr, rs, &["A", "B", "take_A_B", "take_A_C"], &[]); } @@ -4276,7 +4280,7 @@ fn test_nested_type_constructor() { }; "}; let rs = quote! { - ffi::A_B::new(&ffi::make_string("Hello")).within_unique_ptr(); + ffi::A_B::new(ffi::make_string("Hello").as_cpp_ref()).within_unique_ptr(); }; run_test("", hdr, rs, &["A_B"], &[]); } @@ -4301,7 +4305,7 @@ fn test_generic_type() { let rs = quote! { use ffi::ToCppString; let item = ffi::Secondary::new().within_unique_ptr(); - assert_eq!(item.take_c("hello".into_cpp()), 15) + assert_eq!(item.as_cpp_ref().take_c("hello".into_cpp()), 15) }; run_test("", hdr, rs, &["Secondary"], &[]); } @@ -4350,9 +4354,9 @@ fn test_virtual_fns() { "}; let rs = quote! { let mut a = ffi::A::new(12).within_unique_ptr(); - assert_eq!(a.pin_mut().foo(2), 3); + assert_eq!(a.as_cpp_mut_ref().foo(2), 3); let mut b = ffi::B::new().within_unique_ptr(); - assert_eq!(b.pin_mut().foo(2), 4); + assert_eq!(b.as_cpp_mut_ref().foo(2), 4); }; run_test("", hdr, rs, &["A", "B"], &[]); } @@ -4377,9 +4381,9 @@ fn test_const_virtual_fns() { "}; let rs = quote! { let a = ffi::A::new(12).within_unique_ptr(); - assert_eq!(a.foo(2), 3); + assert_eq!(a.as_cpp_ref().foo(2), 3); let b = ffi::B::new().within_unique_ptr(); - assert_eq!(b.foo(2), 4); + assert_eq!(b.as_cpp_ref().foo(2), 4); }; run_test("", hdr, rs, &["A", "B"], &[]); } @@ -4404,7 +4408,7 @@ fn test_virtual_fns_inheritance() { "}; let rs = quote! { let mut b = ffi::B::new().within_unique_ptr(); - assert_eq!(b.pin_mut().foo(2), 3); + assert_eq!(b.as_cpp_mut_ref().foo(2), 3); }; run_test("", hdr, rs, &["B"], &[]); } @@ -4785,7 +4789,7 @@ fn test_dependent_qualified_type() { "}; let rs = quote! { let sv = ffi::make_string_view(); - assert_eq!(ffi::take_string_view(sv.as_ref().unwrap()), 2); + assert_eq!(ffi::take_string_view(sv.as_cpp_ref()), 2); }; run_test("", hdr, rs, &["take_string_view", "make_string_view"], &[]); } @@ -5057,7 +5061,7 @@ fn test_union_ignored() { "}; let rs = quote! { let b = ffi::B::new().within_unique_ptr(); - assert_eq!(b.get_a(), 2); + assert_eq!(b.as_cpp_ref().get_a(), 2); }; run_test("", hdr, rs, &["B"], &[]); } @@ -5199,7 +5203,7 @@ fn test_double_underscore_typedef_ignored() { "}; let rs = quote! { let b = ffi::B::new().within_unique_ptr(); - assert_eq!(b.get_a(), 2); + assert_eq!(b.as_cpp_ref().get_a(), 2); }; run_test("", hdr, rs, &["B"], &[]); } @@ -5371,7 +5375,7 @@ fn test_get_pure_virtual() { "}; let rs = quote! { let a = ffi::get_a(); - let a_ref = unsafe { a.as_ref() }.unwrap(); + let a_ref = CppRef::from_ptr(a); assert_eq!(a_ref.get_val(), 3); }; run_test("", hdr, rs, &["A", "get_a"], &[]); @@ -5678,7 +5682,7 @@ fn test_string_transparent_method() { "}; let rs = quote! { let a = ffi::A::new().within_unique_ptr(); - assert_eq!(a.take_string("hello"), 5); + assert_eq!(a.as_cpp_ref().take_string("hello"), 5); }; run_test("", hdr, rs, &["A"], &[]); } @@ -6356,6 +6360,8 @@ fn test_include_cpp_alone() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] + use autocxx::include_cpp; include_cpp! { #hexathorpe include "input.h" @@ -6379,6 +6385,7 @@ fn test_include_cpp_in_path() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) @@ -6435,7 +6442,7 @@ fn test_cint_vector() { "}; let rs = quote! { - assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[1,2]); + assert_eq!(ffi::give_vec().as_slice(), &[1,2]); }; run_test("", hdr, rs, &["give_vec"], &[]); @@ -6452,7 +6459,7 @@ fn test_int_vector() { "}; let rs = quote! { - assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]); + assert_eq!(ffi::give_vec().as_cpp_ref().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]); }; run_test("", hdr, rs, &["give_vec"], &[]); @@ -6702,6 +6709,7 @@ fn test_two_mods() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; include_cpp! { #hexathorpe include "input.h" @@ -6738,6 +6746,7 @@ fn test_manual_bridge() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) @@ -6776,6 +6785,7 @@ fn test_manual_bridge_mixed_types() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; autocxx::include_cpp! { #hexathorpe include "input.h" @@ -6793,7 +6803,7 @@ fn test_manual_bridge_mixed_types() { } fn main() { let a = ffi2::give_A(); - assert_eq!(ffi::take_A(&a), autocxx::c_int(5)); + assert_eq!(ffi::take_A(a.as_cpp_ref()), autocxx::c_int(5)); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -6816,6 +6826,7 @@ fn test_extern_cpp_type_cxx_bridge() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; include_cpp! { #hexathorpe include "input.h" @@ -6834,7 +6845,7 @@ fn test_extern_cpp_type_cxx_bridge() { } fn main() { let a = ffi::create_a(); - ffi::handle_a(&a); + ffi::handle_a(a.as_cpp_ref()); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -6857,6 +6868,7 @@ fn test_extern_cpp_type_different_name() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; include_cpp! { #hexathorpe include "input.h" @@ -6876,7 +6888,7 @@ fn test_extern_cpp_type_different_name() { pub use ffi2::A as DifferentA; fn main() { let a = ffi::create_a(); - ffi::handle_a(&a); + ffi::handle_a(a.as_cpp_ref()); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -6902,6 +6914,8 @@ fn test_extern_cpp_type_two_include_cpp() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] + use autocxx::prelude::*; pub mod base { autocxx::include_cpp! { #hexathorpe include "input.h" @@ -6926,8 +6940,8 @@ fn test_extern_cpp_type_two_include_cpp() { } fn main() { use autocxx::prelude::*; - let a = dependent::create_a(base::B::VARIANT).within_box(); - dependent::handle_a(&a); + let a = dependent::create_a(base::B::VARIANT).within_unique_ptr(); + dependent::handle_a(a.as_cpp_ref()); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -6950,6 +6964,8 @@ fn test_extern_cpp_type_namespace() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] + use autocxx::prelude::*; pub mod b { autocxx::include_cpp! { #hexathorpe include "input.h" @@ -6971,7 +6987,7 @@ fn test_extern_cpp_type_namespace() { } fn main() { use autocxx::prelude::*; - let _ = crate::a::A::new().within_unique_ptr().as_mut().unwrap().make_b(); + let _ = crate::a::A::new().within_unique_ptr().as_cpp_ref().const_cast().make_b(); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -6994,6 +7010,7 @@ fn test_extern_cpp_type_manual() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) @@ -7120,8 +7137,8 @@ fn test_rust_reference() { } "}; let rs = quote! { - let foo = RustType(3); - assert_eq!(ffi::take_rust_reference(&foo), 4); + let foo = CppPin::new(RustType(3)); + assert_eq!(ffi::take_rust_reference(foo.as_cpp_ref()), 4); }; run_test_ex( "", @@ -7150,8 +7167,8 @@ fn test_rust_reference_autodiscover() { } "}; let rs = quote! { - let foo = RustType(3); - let result = ffi::take_rust_reference(&foo); + let foo = CppPin::new(RustType(3)); + let result = ffi::take_rust_reference(foo.as_cpp_ref()); assert_eq!(result, 4); }; run_test_ex( @@ -7210,8 +7227,8 @@ fn test_extern_rust_method() { return foo.get(); }"}; let rs = quote! { - let a = RustType(74); - assert_eq!(ffi::examine(&a), 74); + let a = autocxx::CppPin::new(RustType(74)); + assert_eq!(ffi::examine(a.as_cpp_ref()), 74); }; run_test_ex( cxx, @@ -7240,6 +7257,7 @@ fn test_extern_rust_fn_callback() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) @@ -7273,8 +7291,8 @@ fn test_rust_reference_no_autodiscover() { } "}; let rs = quote! { - let foo = RustType(3); - let result = ffi::take_rust_reference(&foo); + let foo = CppPin::new(RustType(3)); + let result = ffi::take_rust_reference(foo.as_cpp_ref()); assert_eq!(result, 4); }; run_test_ex( @@ -7471,6 +7489,7 @@ fn test_box_via_extern_rust_no_include_cpp() { "", hdr, quote! { + #![feature(arbitrary_self_types)] #[autocxx::extern_rust::extern_rust_type] pub struct Foo { a: String, @@ -8207,6 +8226,7 @@ fn test_subclass_no_safety() { "}; let hexathorpe = Token![#](Span::call_site()); let unexpanded_rust = quote! { + #![feature(arbitrary_self_types)] use autocxx::prelude::*; include_cpp!( @@ -8365,7 +8385,7 @@ fn test_pv_subclass_allocation_not_self_owned() { assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated); assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated); assert!(!Lazy::force(&STATUS).lock().unwrap().a_called); - let obs_superclass = obs.as_ref().unwrap(); // &subclass + let obs_superclass = obs.as_cpp_ref(); // &subclass let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) }; ffi::TriggerTestObserverA(obs_superclass); assert!(Lazy::force(&STATUS).lock().unwrap().a_called); @@ -8500,7 +8520,7 @@ fn test_pv_subclass_allocation_self_owned() { assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated); assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated); assert!(!Lazy::force(&STATUS).lock().unwrap().a_called); - let obs_superclass = obs.as_ref().unwrap(); // &subclass + let obs_superclass = obs.as_cpp_ref(); // &subclass let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) }; ffi::TriggerTestObserverA(obs_superclass); @@ -8538,7 +8558,7 @@ fn test_pv_subclass_allocation_self_owned() { assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated); assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated); assert!(!Lazy::force(&STATUS).lock().unwrap().a_called); - ffi::TriggerTestObserverA(unsafe { obs_superclass_ptr.as_ref().unwrap() }); + ffi::TriggerTestObserverA(unsafe { obs_superclass_ptr.as_cpp_ref() }); assert!(Lazy::force(&STATUS).lock().unwrap().a_called); assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated); @@ -8685,7 +8705,7 @@ fn test_pv_subclass_calls() { let obs = MyTestObserver::new_rust_owned( MyTestObserver::default() ); - ffi::register_observer(obs.as_ref().borrow_mut().pin_mut()); + ffi::register_observer(obs.as_ref().borrow_mut().as_cpp_mut_ref()); assert_eq!(ffi::call_a(1), 2); assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called); *Lazy::force(&STATUS).lock().unwrap() = Default::default(); @@ -8973,7 +8993,7 @@ fn test_pv_subclass_types() { let obs = MyTestObserver::new_rust_owned( MyTestObserver::default() ); - ffi::register_observer(obs.as_ref().borrow_mut().pin_mut()); + ffi::register_observer(obs.as_ref().borrow_mut().as_cpp_mut_ref()); ffi::call_p(ffi::Pod { a: 3 }); ffi::call_s("hello"); ffi::call_n(ffi::make_non_pod("goodbye").within_unique_ptr()); @@ -9046,7 +9066,7 @@ fn test_pv_subclass_constructors() { let obs = MyTestObserver::new_rust_owned( MyTestObserver::default() ); - ffi::register_observer(obs.as_ref().borrow_mut().pin_mut()); + ffi::register_observer(obs.as_ref().borrow_mut().as_cpp_mut_ref()); ffi::do_a_thing(); }, quote! { @@ -9147,7 +9167,7 @@ fn test_non_pv_subclass_overloads() { let obs = MyTestObserver::new_rust_owned( MyTestObserver::default() ); - ffi::register_observer(obs.as_ref().borrow_mut().pin_mut()); + ffi::register_observer(obs.as_ref().borrow_mut().as_cpp_mut_ref()); ffi::do_a_thing(); }, quote! { @@ -9204,7 +9224,7 @@ fn test_pv_subclass_overrides() { let obs = MyTestObserver::new_rust_owned( MyTestObserver::default() ); - ffi::register_observer(obs.as_ref().borrow_mut().pin_mut()); + ffi::register_observer(obs.as_ref().borrow_mut().as_cpp_mut_ref()); ffi::do_a_thing(); }, quote! { @@ -9303,7 +9323,7 @@ fn test_constructor_moveit() { moveit! { let mut stack_obj = ffi::A::new(); } - stack_obj.as_mut().set(42); + stack_obj.set(42); assert_eq!(stack_obj.get(), 42); }; run_test("", hdr, rs, &["A"], &[]); @@ -9390,7 +9410,7 @@ fn test_implicit_constructor_moveit() { let mut stack_obj = ffi::A::new(); } stack_obj.as_mut().set(42); - assert_eq!(stack_obj.get(), 42); + assert_eq!(stack_obj.as_ref().get(), 42); }; run_test("", hdr, rs, &["A"], &[]); } @@ -9425,9 +9445,9 @@ fn test_pass_by_value_moveit() { // A has no move constructor so we can't consume it. let heap_obj = ffi::A::new().within_unique_ptr(); - ffi::take_a(heap_obj.as_ref().unwrap()); + ffi::take_a(heap_obj.as_cpp_ref()); ffi::take_a(&heap_obj); - ffi::take_a(autocxx::as_copy(heap_obj.as_ref().unwrap())); + ffi::take_a(autocxx::as_copy(heap_obj.as_cpp_ref())); ffi::take_a(heap_obj); // consume let heap_obj2 = ffi::A::new().within_box(); @@ -9466,7 +9486,7 @@ fn test_nonconst_reference_parameter() { "}; let rs = quote! { let mut heap_obj = ffi::A::new().within_unique_ptr(); - ffi::take_a(heap_obj.pin_mut()); + ffi::take_a(heap_obj.as_cpp_ref().const_cast()); }; run_test("", hdr, rs, &["NOP", "A", "take_a"], &[]); } @@ -9490,7 +9510,7 @@ fn test_nonconst_reference_method_parameter() { let rs = quote! { let mut a = ffi::A::new().within_unique_ptr(); let b = ffi::B::new().within_unique_ptr(); - b.take_a(a.pin_mut()); + b.as_cpp_ref().take_a(a.as_cpp_ref().const_cast()); }; run_test("", hdr, rs, &["NOP", "A", "B"], &[]); } @@ -9565,7 +9585,7 @@ fn test_copy_and_move_constructor_moveit() { moveit! { let mut stack_obj = ffi::A::new(); } - stack_obj.as_mut().set(42); + stack_obj.set(42); moveit! { let stack_obj2 = autocxx::moveit::new::copy(stack_obj.as_ref()); } @@ -9600,8 +9620,8 @@ fn test_uniqueptr_moveit() { let rs = quote! { use autocxx::moveit::Emplace; let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new()); - up_obj.as_mut().unwrap().set(42); - assert_eq!(up_obj.get(), 42); + up_obj.as_cpp_ref().const_cast().set(42); + assert_eq!(up_obj.as_cpp_ref().get(), 42); }; run_test("", hdr, rs, &["A"], &[]); } @@ -9720,7 +9740,7 @@ fn test_pass_by_reference_to_value_param() { let a = ffi::A::new().within_unique_ptr(); ffi::take_a(a.as_ref().unwrap()); ffi::take_a(&a); // syntactic sugar - assert_eq!(ffi::report_on_a(&a), 0); // should have acted upon copies + assert_eq!(ffi::report_on_a(a.as_cpp_ref()), 0); // should have acted upon copies }; run_test("", hdr, rs, &["A", "take_a", "report_on_a"], &[]); } @@ -9881,7 +9901,7 @@ fn test_abstract_up_single_bridge() { "}; let rs = quote! { let a = ffi::get_a(); - a.foo(); + a.as_cpp_ref().foo(); }; run_test("", hdr, rs, &["A", "get_a"], &[]); } @@ -9903,6 +9923,8 @@ fn test_abstract_up_multiple_bridge() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] + use autocxx::prelude::*; autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) @@ -9917,7 +9939,7 @@ fn test_abstract_up_multiple_bridge() { } fn main() { let a = ffi2::get_a(); - a.foo(); + a.as_cpp_ref().foo(); } }; do_run_test_manual("", hdr, rs, None, None).unwrap(); @@ -10133,8 +10155,8 @@ fn test_nested_class_methods() { "}; let rs = quote! { let a = ffi::A::new().within_unique_ptr(); - a.a(); - a.c(); + a.as_cpp_ref().a(); + a.as_cpp_ref().c(); }; run_test("", hdr, rs, &["A"], &[]); } @@ -10156,7 +10178,7 @@ fn test_call_superclass() { "}; let rs = quote! { let b = ffi::get_b(); - b.as_ref().unwrap().as_ref().foo(); + b.as_cpp_ref().foo(); }; run_test("", hdr, rs, &["A", "B", "get_b"], &[]); } @@ -10179,7 +10201,7 @@ fn test_pass_superclass() { "}; let rs = quote! { let b = ffi::get_b(); - ffi::take_a(b.as_ref().unwrap().as_ref()); + ffi::take_a(b.as_cpp_ref().as_ref()); }; run_test("", hdr, rs, &["A", "B", "get_b", "take_a"], &[]); } @@ -11412,7 +11434,7 @@ fn test_tricky_destructors() { let mut unique_t = <$t>::new().within_unique_ptr(); let mut destructor_flag = false; unsafe { - unique_t.pin_mut().set_flag(&mut destructor_flag); + unique_t.as_cpp_mut_ref().set_flag(&mut destructor_flag); } std::mem::drop(unique_t); assert!(destructor_flag, "Destructor did not run with make_unique for {}", quote::quote!{$t}); @@ -11422,7 +11444,7 @@ fn test_tricky_destructors() { } let mut destructor_flag = false; unsafe { - moveit_t.as_mut().set_flag(&mut destructor_flag); + moveit_t.as_cpp_mut_ref().set_flag(&mut destructor_flag); } std::mem::drop(moveit_t); assert!(destructor_flag, "Destructor did not run with moveit for {}", quote::quote!{$t}); @@ -12271,6 +12293,7 @@ fn test_issue_1229() { "}; let hexathorpe = Token![#](Span::call_site()); let rs = quote! { + #![feature(arbitrary_self_types)] use autocxx::WithinUniquePtr; autocxx::include_cpp! { diff --git a/parser/src/config.rs b/parser/src/config.rs index 2421e09a6..785ae042b 100644 --- a/parser/src/config.rs +++ b/parser/src/config.rs @@ -31,7 +31,6 @@ use quote::quote; #[derive(PartialEq, Eq, Clone, Debug, Hash)] pub enum UnsafePolicy { - AllFunctionsSafe, AllFunctionsUnsafe, ReferencesWrappedAllFunctionsSafe, } @@ -45,12 +44,12 @@ impl Default for UnsafePolicy { impl Parse for UnsafePolicy { fn parse(input: ParseStream) -> ParseResult { if input.parse::>()?.is_some() { - return Ok(UnsafePolicy::AllFunctionsSafe); + return Ok(UnsafePolicy::ReferencesWrappedAllFunctionsSafe); } let r = match input.parse::>()? { Some(id) => { if id == "unsafe_ffi" { - Ok(UnsafePolicy::AllFunctionsSafe) + Ok(UnsafePolicy::ReferencesWrappedAllFunctionsSafe) } else if id == "unsafe_references_wrapped" { Ok(UnsafePolicy::ReferencesWrappedAllFunctionsSafe) } else { @@ -74,9 +73,7 @@ impl Parse for UnsafePolicy { impl ToTokens for UnsafePolicy { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - if *self == UnsafePolicy::AllFunctionsSafe { - tokens.extend(quote! { unsafe }) - } else if *self == UnsafePolicy::ReferencesWrappedAllFunctionsSafe { + if *self == UnsafePolicy::ReferencesWrappedAllFunctionsSafe { tokens.extend(quote! { unsafe_references_wrapped }) } } @@ -503,7 +500,7 @@ mod parse_tests { let us: UnsafePolicy = parse_quote! { unsafe }; - assert_eq!(us, UnsafePolicy::AllFunctionsSafe) + assert_eq!(us, UnsafePolicy::ReferencesWrappedAllFunctionsSafe) } #[test] @@ -511,7 +508,7 @@ mod parse_tests { let us: UnsafePolicy = parse_quote! { unsafe_ffi }; - assert_eq!(us, UnsafePolicy::AllFunctionsSafe) + assert_eq!(us, UnsafePolicy::ReferencesWrappedAllFunctionsSafe) } #[test] diff --git a/src/reference_wrapper.rs b/src/reference_wrapper.rs index 2baeaaa87..4252100b1 100644 --- a/src/reference_wrapper.rs +++ b/src/reference_wrapper.rs @@ -22,10 +22,6 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// UB here cannot manifest within Rust, but only across in C++, and therefore /// they are equivalently safe to using C++ references in pure-C++ codebases. /// -/// *Important*: you might be wondering why you've never encountered this type. -/// These exist in autocxx-generated bindings only if the `unsafe_references_wrapped` -/// safety policy is given. This may become the default in future. -/// /// # Usage /// /// These types of references are pretty useless in Rust. You can't do