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| &param.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;
                 }
diff --git a/engine/src/conversion/api.rs b/engine/src/conversion/api.rs
index 3d04674..c5a1b60 100644
--- a/engine/src/conversion/api.rs
+++ b/engine/src/conversion/api.rs
@@ -54,7 +54,6 @@
 
 /// Details about a C++ struct.
 pub(crate) struct StructDetails {
-    pub(crate) vis: CppVisibility,
     pub(crate) item: ItemStruct,
     pub(crate) layout: Option<Layout>,
     pub(crate) has_rvalue_reference_fields: bool,
@@ -713,3 +712,10 @@
         Ok(Box::new(std::iter::once(Api::Enum { name, item })))
     }
 }
+
+/// Whether a type is a pointer of some kind.
+pub(crate) enum Pointerness {
+    Not,
+    ConstPtr,
+    MutPtr,
+}
diff --git a/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs b/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
index b2e1ea3..5367626 100644
--- a/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
+++ b/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
@@ -6,8 +6,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use syn::{Type, TypePtr};
+
 use crate::conversion::{
     analysis::fun::function_wrapper::{CppConversionType, TypeConversionPolicy},
+    api::Pointerness,
     ConvertError,
 };
 
@@ -30,12 +33,39 @@
     pub(super) fn converted_type(&self, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
         match self.cpp_conversion {
             CppConversionType::FromValueToUniquePtr => self.unique_ptr_wrapped_type(cpp_name_map),
+            CppConversionType::FromReferenceToPointer => {
+                let (const_string, ty) = match self.cxxbridge_type() {
+                    Type::Ptr(TypePtr {
+                        mutability: Some(_),
+                        elem,
+                        ..
+                    }) => ("", elem.as_ref()),
+                    Type::Ptr(TypePtr { elem, .. }) => ("const ", elem.as_ref()),
+                    _ => panic!("Not a pointer"),
+                };
+                Ok(format!(
+                    "{}{}*",
+                    const_string,
+                    type_to_cpp(ty, cpp_name_map)?
+                ))
+            }
             _ => self.unwrapped_type_as_string(cpp_name_map),
         }
     }
 
     fn unwrapped_type_as_string(&self, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
-        type_to_cpp(&self.unwrapped_type, cpp_name_map)
+        type_to_cpp(self.cxxbridge_type(), cpp_name_map)
+    }
+
+    pub(crate) fn is_a_pointer(&self) -> Pointerness {
+        match self.cxxbridge_type() {
+            Type::Ptr(TypePtr {
+                mutability: Some(_),
+                ..
+            }) => Pointerness::MutPtr,
+            Type::Ptr(_) => Pointerness::ConstPtr,
+            _ => Pointerness::Not,
+        }
     }
 
     fn unique_ptr_wrapped_type(
@@ -60,6 +90,7 @@
             CppConversionType::None | CppConversionType::FromReturnValueToPlacementPtr => {
                 Some(var_name.to_string())
             }
+            CppConversionType::FromPointerToReference { .. } => Some(format!("(*{})", var_name)),
             CppConversionType::Move => Some(format!("std::move({})", var_name)),
             CppConversionType::FromUniquePtrToValue | CppConversionType::FromPtrToMove => {
                 Some(format!("std::move(*{})", var_name))
@@ -78,6 +109,7 @@
                 })
             }
             CppConversionType::IgnoredPlacementPtrParameter => None,
+            CppConversionType::FromReferenceToPointer { .. } => Some(format!("&{}", var_name)),
         })
     }
 }
diff --git a/engine/src/conversion/codegen_cpp/mod.rs b/engine/src/conversion/codegen_cpp/mod.rs
index 02e92b2..0e6dcce 100644
--- a/engine/src/conversion/codegen_cpp/mod.rs
+++ b/engine/src/conversion/codegen_cpp/mod.rs
@@ -559,7 +559,7 @@
 
             underlying_function_call = match placement_param {
                 Some(placement_param) => {
-                    let tyname = type_to_cpp(&ret.unwrapped_type, &self.original_name_map)?;
+                    let tyname = type_to_cpp(ret.cxxbridge_type(), &self.original_name_map)?;
                     format!("new({}) {}({})", placement_param, tyname, call_itself)
                 }
                 None => format!("return {}", call_itself),
@@ -684,6 +684,13 @@
             "{}& As_{}_mut() {{ return *this; }}",
             super_name, super_name
         ));
+        self.additional_functions.push(ExtraCpp {
+            declaration: Some(format!(
+                "inline std::unique_ptr<{}> {}_As_{}_UniquePtr(std::unique_ptr<{}> u) {{ return std::unique_ptr<{}>(u.release()); }}",
+                superclass.to_cpp_name(), subclass.cpp(), super_name, subclass.cpp(), superclass.to_cpp_name(),
+                )),
+                ..Default::default()
+        });
         // And now constructors
         let mut constructor_decls: Vec<String> = Vec::new();
         for constructor in constructors {
@@ -700,7 +707,7 @@
         }
         self.additional_functions.push(ExtraCpp {
             type_definition: Some(format!(
-                "class {} : {}\n{{\npublic:\n{}\n{}\nvoid {}() const;\nprivate:rust::Box<{}> obs;\nvoid really_remove_ownership();\n\n}};",
+                "class {} : public {}\n{{\npublic:\n{}\n{}\nvoid {}() const;\nprivate:rust::Box<{}> obs;\nvoid really_remove_ownership();\n\n}};",
                 subclass.cpp(),
                 superclass.to_cpp_name(),
                 constructor_decls.join("\n"),
diff --git a/engine/src/conversion/codegen_rs/fun_codegen.rs b/engine/src/conversion/codegen_rs/fun_codegen.rs
index 7c32b1b..db222a6 100644
--- a/engine/src/conversion/codegen_rs/fun_codegen.rs
+++ b/engine/src/conversion/codegen_rs/fun_codegen.rs
@@ -6,6 +6,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use autocxx_parser::IncludeCppConfig;
 use indexmap::set::IndexSet as HashSet;
 use std::borrow::Cow;
 
@@ -23,15 +24,15 @@
     function_wrapper_rs::RustParamConversion,
     maybe_unsafes_to_tokens,
     unqualify::{unqualify_params, unqualify_ret_type},
-    ImplBlockDetails, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, Use,
+    ImplBlockDetails, ImplBlockKey, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, Use,
 };
 use crate::{
     conversion::{
         analysis::fun::{
-            ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
-            TraitMethodDetails,
+            function_wrapper::TypeConversionPolicy, ArgumentAnalysis, FnAnalysis, FnKind,
+            MethodKind, RustRenameStrategy, TraitMethodDetails,
         },
-        api::UnsafetyNeeded,
+        api::{Pointerness, UnsafetyNeeded},
     },
     types::{Namespace, QualifiedName},
 };
@@ -89,6 +90,7 @@
     analysis: FnAnalysis,
     cpp_call_name: String,
     non_pod_types: &HashSet<QualifiedName>,
+    config: &IncludeCppConfig,
 ) -> RsCodegenResult {
     if analysis.ignore_reason.is_err() || !analysis.externally_callable {
         return RsCodegenResult::default();
@@ -96,6 +98,7 @@
     let cxxbridge_name = analysis.cxxbridge_name;
     let rust_name = &analysis.rust_name;
     let ret_type = analysis.ret_type;
+    let ret_conversion = analysis.ret_conversion;
     let param_details = analysis.param_details;
     let wrapper_function_needed = analysis.cpp_wrapper.is_some();
     let params = analysis.params;
@@ -119,6 +122,9 @@
         always_unsafe_due_to_trait_definition,
         doc_attrs: &doc_attrs,
         non_pod_types,
+        ret_type: &ret_type,
+        ret_conversion: &ret_conversion,
+        reference_wrappers: config.unsafe_policy.requires_cpprefs(),
     };
     // In rare occasions, we might need to give an explicit lifetime.
     let (lifetime_tokens, params, ret_type) = add_explicit_lifetime_if_necessary(
@@ -148,15 +154,14 @@
                 impl_entry = Some(fn_generator.generate_method_impl(
                     matches!(method_kind, MethodKind::Constructor { .. }),
                     impl_for,
-                    &ret_type,
                 ));
             }
             FnKind::TraitMethod { ref details, .. } => {
-                trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
+                trait_impl_entry = Some(fn_generator.generate_trait_impl(details));
             }
             _ => {
                 // Generate plain old function
-                bindgen_mod_items.push(fn_generator.generate_function_impl(&ret_type));
+                bindgen_mod_items.push(fn_generator.generate_function_impl());
             }
         }
     }
@@ -225,20 +230,23 @@
 #[derive(Clone)]
 struct FnGenerator<'a> {
     param_details: &'a [ArgumentAnalysis],
+    ret_conversion: &'a Option<TypeConversionPolicy>,
+    ret_type: &'a ReturnType,
     cxxbridge_name: &'a Ident,
     rust_name: &'a str,
     unsafety: &'a UnsafetyNeeded,
     always_unsafe_due_to_trait_definition: bool,
     doc_attrs: &'a Vec<Attribute>,
     non_pod_types: &'a HashSet<QualifiedName>,
+    reference_wrappers: bool,
 }
 
 impl<'a> FnGenerator<'a> {
     fn common_parts<'b>(
-        &self,
+        &'b self,
         avoid_self: bool,
         parameter_reordering: &Option<Vec<usize>>,
-        ret_type: &'b ReturnType,
+        ret_type: Option<ReturnType>,
     ) -> (
         Option<TokenStream>,
         Punctuated<FnArg, Comma>,
@@ -249,15 +257,20 @@
         let mut local_variables = Vec::new();
         let mut arg_list = Vec::new();
         let mut ptr_arg_name = None;
-        let mut ret_type = Cow::Borrowed(ret_type);
+        let mut ret_type: Cow<'a, _> = ret_type
+            .map(Cow::Owned)
+            .unwrap_or(Cow::Borrowed(self.ret_type));
         let mut any_conversion_requires_unsafe = false;
+        let mut variable_counter = 0usize;
         for pd in self.param_details {
             let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self {
                 parse_quote!(self)
             } else {
                 pd.name.clone()
             };
-            let rust_for_param = pd.conversion.rust_conversion(wrapper_arg_name.clone());
+            let rust_for_param = pd
+                .conversion
+                .rust_conversion(parse_quote! { #wrapper_arg_name }, &mut variable_counter);
             match rust_for_param {
                 RustParamConversion::Param {
                     ty,
@@ -305,6 +318,39 @@
             },
             any_conversion_requires_unsafe || matches!(self.unsafety, UnsafetyNeeded::JustBridge),
         );
+        let context_is_unsafe = matches!(self.unsafety, UnsafetyNeeded::Always)
+            || self.always_unsafe_due_to_trait_definition;
+        let (call_body, ret_type) = match self.ret_conversion {
+            Some(ret_conversion) if ret_conversion.rust_work_needed() => {
+                let expr = maybe_unsafes_to_tokens(vec![call_body], context_is_unsafe);
+                let conv =
+                    ret_conversion.rust_conversion(parse_quote! { #expr }, &mut variable_counter);
+                let (conversion, requires_unsafe, ty) = match conv {
+                    RustParamConversion::Param {
+                        local_variables, ..
+                    } if !local_variables.is_empty() => panic!("return type required variables"),
+                    RustParamConversion::Param {
+                        conversion,
+                        conversion_requires_unsafe,
+                        ty,
+                        ..
+                    } => (conversion, conversion_requires_unsafe, ty),
+                    _ => panic!(
+                        "Unexpected - return type is supposed to be converted to a return type"
+                    ),
+                };
+                (
+                    if requires_unsafe {
+                        MaybeUnsafeStmt::NeedsUnsafe(conversion)
+                    } else {
+                        MaybeUnsafeStmt::Normal(conversion)
+                    },
+                    Cow::Owned(parse_quote! { -> #ty }),
+                )
+            }
+            _ => (call_body, ret_type),
+        };
+
         let call_stmts = if let Some(ptr_arg_name) = ptr_arg_name {
             let mut closure_stmts = local_variables;
             closure_stmts.push(MaybeUnsafeStmt::binary(
@@ -323,8 +369,6 @@
             call_stmts.push(call_body);
             call_stmts
         };
-        let context_is_unsafe = matches!(self.unsafety, UnsafetyNeeded::Always)
-            || self.always_unsafe_due_to_trait_definition;
         let call_body = maybe_unsafes_to_tokens(call_stmts, context_is_unsafe);
         (lifetime_tokens, wrapper_params, ret_type, call_body)
     }
@@ -334,13 +378,44 @@
         &self,
         avoid_self: bool,
         impl_block_type_name: &QualifiedName,
-        ret_type: &ReturnType,
     ) -> Box<ImplBlockDetails> {
         let (lifetime_tokens, wrapper_params, ret_type, call_body) =
-            self.common_parts(avoid_self, &None, ret_type);
+            self.common_parts(avoid_self, &None, None);
         let rust_name = make_ident(self.rust_name);
         let unsafety = self.unsafety.wrapper_token();
         let doc_attrs = self.doc_attrs;
+        let receiver_pointerness = self
+            .param_details
+            .iter()
+            .next()
+            .map(|pd| pd.conversion.is_a_pointer())
+            .unwrap_or(Pointerness::Not);
+        let ty = impl_block_type_name.get_final_ident();
+        let ty = if self.reference_wrappers {
+            match receiver_pointerness {
+                Pointerness::MutPtr => ImplBlockKey {
+                    ty: parse_quote! {
+                        CppMutRef< 'a, #ty>
+                    },
+                    lifetime: Some(parse_quote! { 'a }),
+                },
+                Pointerness::ConstPtr => ImplBlockKey {
+                    ty: parse_quote! {
+                        CppRef< 'a, #ty>
+                    },
+                    lifetime: Some(parse_quote! { 'a }),
+                },
+                Pointerness::Not => ImplBlockKey {
+                    ty: parse_quote! { # ty },
+                    lifetime: None,
+                },
+            }
+        } else {
+            ImplBlockKey {
+                ty: parse_quote! { # ty },
+                lifetime: None,
+            }
+        };
         Box::new(ImplBlockDetails {
             item: ImplItem::Method(parse_quote! {
                 #(#doc_attrs)*
@@ -348,18 +423,14 @@
                     #call_body
                 }
             }),
-            ty: impl_block_type_name.get_final_ident(),
+            ty,
         })
     }
 
     /// Generate an 'impl Trait for Type { methods-go-here }' in its entrety.
-    fn generate_trait_impl(
-        &self,
-        details: &TraitMethodDetails,
-        ret_type: &ReturnType,
-    ) -> Box<TraitImplBlockDetails> {
+    fn generate_trait_impl(&self, details: &TraitMethodDetails) -> Box<TraitImplBlockDetails> {
         let (lifetime_tokens, wrapper_params, ret_type, call_body) =
-            self.common_parts(details.avoid_self, &details.parameter_reordering, ret_type);
+            self.common_parts(details.avoid_self, &details.parameter_reordering, None);
         let doc_attrs = self.doc_attrs;
         let unsafety = self.unsafety.wrapper_token();
         let key = details.trt.clone();
@@ -381,25 +452,28 @@
     ) -> Box<ImplBlockDetails> {
         let ret_type: ReturnType = parse_quote! { -> impl autocxx::moveit::new::New<Output=Self> };
         let (lifetime_tokens, wrapper_params, ret_type, call_body) =
-            self.common_parts(true, &None, &ret_type);
+            self.common_parts(true, &None, Some(ret_type));
         let rust_name = make_ident(&self.rust_name);
         let doc_attrs = self.doc_attrs;
         let unsafety = self.unsafety.wrapper_token();
-        Box::new(ImplBlockDetails {
-            item: ImplItem::Method(parse_quote! {
+        let ty = impl_block_type_name.get_final_ident();
+        let ty = parse_quote! { #ty };
+        let stuff = quote! {
                 #(#doc_attrs)*
                 pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                     #call_body
                 }
-            }),
-            ty: impl_block_type_name.get_final_ident(),
+        };
+        Box::new(ImplBlockDetails {
+            item: ImplItem::Method(parse_quote! { #stuff }),
+            ty: ImplBlockKey { ty, lifetime: None },
         })
     }
 
     /// Generate a function call wrapper
-    fn generate_function_impl(&self, ret_type: &ReturnType) -> Item {
+    fn generate_function_impl(&self) -> Item {
         let (lifetime_tokens, wrapper_params, ret_type, call_body) =
-            self.common_parts(false, &None, ret_type);
+            self.common_parts(false, &None, None);
         let rust_name = make_ident(self.rust_name);
         let doc_attrs = self.doc_attrs;
         let unsafety = self.unsafety.wrapper_token();
diff --git a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
index a3fc71f..708d41c 100644
--- a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
+++ b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
@@ -7,7 +7,7 @@
 // except according to those terms.
 
 use proc_macro2::TokenStream;
-use syn::{Pat, Type, TypePtr};
+use syn::{Expr, Type, TypePtr};
 
 use crate::{
     conversion::analysis::fun::function_wrapper::{RustConversionType, TypeConversionPolicy},
@@ -32,8 +32,7 @@
 }
 
 impl TypeConversionPolicy {
-    /// If returns `None` then this parameter should be omitted entirely.
-    pub(super) fn rust_conversion(&self, var: Pat) -> RustParamConversion {
+    pub(super) fn rust_conversion(&self, var: Expr, counter: &mut usize) -> RustParamConversion {
         match self.rust_conversion {
             RustConversionType::None => RustParamConversion::Param {
                 ty: self.converted_rust_type(),
@@ -63,7 +62,7 @@
                 }
             }
             RustConversionType::FromPinMaybeUninitToPtr => {
-                let ty = match &self.unwrapped_type {
+                let ty = match self.cxxbridge_type() {
                     Type::Ptr(TypePtr { elem, .. }) => &*elem,
                     _ => panic!("Not a ptr"),
                 };
@@ -80,7 +79,7 @@
                 }
             }
             RustConversionType::FromPinMoveRefToPtr => {
-                let ty = match &self.unwrapped_type {
+                let ty = match self.cxxbridge_type() {
                     Type::Ptr(TypePtr { elem, .. }) => &*elem,
                     _ => panic!("Not a ptr"),
                 };
@@ -99,7 +98,7 @@
                 }
             }
             RustConversionType::FromTypeToPtr => {
-                let ty = match &self.unwrapped_type {
+                let ty = match self.cxxbridge_type() {
                     Type::Ptr(TypePtr { elem, .. }) => &*elem,
                     _ => panic!("Not a ptr"),
                 };
@@ -123,13 +122,11 @@
                 };
                 let handler_type = make_ident(handler_type);
                 let param_trait = make_ident(param_trait);
-                let var_name = if let Pat::Ident(pti) = &var {
-                    &pti.ident
-                } else {
-                    panic!("Unexpected non-ident parameter name");
-                };
-                let space_var_name = make_ident(format!("{}_space", var_name));
-                let ty = &self.unwrapped_type;
+                let var_counter = *counter;
+                *counter += 1;
+                let space_var_name = format!("space{}", var_counter);
+                let space_var_name = make_ident(space_var_name);
+                let ty = self.cxxbridge_type();
                 let ty = parse_quote! { impl autocxx::#param_trait<#ty> };
                 // This is the usual trick to put something on the stack, then
                 // immediately shadow the variable name so it can't be accessed or moved.
@@ -148,7 +145,7 @@
                             },
                         ),
                         MaybeUnsafeStmt::needs_unsafe(
-                            quote! { #space_var_name.as_mut().populate(#var_name); },
+                            quote! { #space_var_name.as_mut().populate(#var); },
                         ),
                     ],
                     conversion: quote! {
@@ -161,12 +158,55 @@
             // but not in the arguments for the wrapper function, because instead we return an
             // impl New which uses the cxx::bridge function's pointer parameter.
             RustConversionType::FromPlacementParamToNewReturn => {
-                let ty = match &self.unwrapped_type {
+                let ty = match self.cxxbridge_type() {
                     Type::Ptr(TypePtr { elem, .. }) => *(*elem).clone(),
                     _ => panic!("Not a ptr"),
                 };
                 RustParamConversion::ReturnValue { ty }
             }
+            RustConversionType::FromPointerToReferenceWrapper => {
+                let (is_mut, ty) = match self.cxxbridge_type() {
+                    Type::Ptr(TypePtr {
+                        mutability, elem, ..
+                    }) => (mutability.is_some(), elem.as_ref()),
+                    _ => panic!("Not a pointer"),
+                };
+                let (ty, wrapper_name) = if is_mut {
+                    (parse_quote! { CppMutRef<'a, #ty> }, "CppMutRef")
+                } else {
+                    (parse_quote! { CppRef<'a, #ty> }, "CppRef")
+                };
+                let wrapper_name = make_ident(wrapper_name);
+                RustParamConversion::Param {
+                    ty,
+                    local_variables: Vec::new(),
+                    conversion: quote! {
+                        #wrapper_name (#var, std::marker::PhantomData)
+                    },
+                    conversion_requires_unsafe: false,
+                }
+            }
+            RustConversionType::FromReferenceWrapperToPointer => {
+                let (is_mut, ty) = match self.cxxbridge_type() {
+                    Type::Ptr(TypePtr {
+                        mutability, elem, ..
+                    }) => (mutability.is_some(), elem.as_ref()),
+                    _ => panic!("Not a pointer"),
+                };
+                let ty = if is_mut {
+                    parse_quote! { &mut CppMutRef<'a, #ty> }
+                } else {
+                    parse_quote! { &CppRef<'a, #ty> }
+                };
+                RustParamConversion::Param {
+                    ty,
+                    local_variables: Vec::new(),
+                    conversion: quote! {
+                        #var .0
+                    },
+                    conversion_requires_unsafe: false,
+                }
+            }
         }
     }
 }
diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs
index d488d52..5dd4cbb 100644
--- a/engine/src/conversion/codegen_rs/mod.rs
+++ b/engine/src/conversion/codegen_rs/mod.rs
@@ -17,13 +17,14 @@
 use indexmap::map::IndexMap as HashMap;
 use indexmap::set::IndexSet as HashSet;
 
-use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun};
+use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun, UnsafePolicy};
 
 use itertools::Itertools;
 use proc_macro2::{Span, TokenStream};
 use syn::{
     parse_quote, punctuated::Punctuated, token::Comma, Attribute, Expr, FnArg, ForeignItem,
-    ForeignItemFn, Ident, ImplItem, Item, ItemForeignMod, ItemMod, TraitItem, TypePath,
+    ForeignItemFn, Ident, ImplItem, Item, ItemForeignMod, ItemMod, Lifetime, TraitItem, Type,
+    TypePath,
 };
 
 use crate::{
@@ -61,10 +62,16 @@
 use super::{convert_error::ErrorContext, ConvertError};
 use quote::quote;
 
+#[derive(Clone, Hash, PartialEq, Eq)]
+struct ImplBlockKey {
+    ty: Type,
+    lifetime: Option<Lifetime>,
+}
+
 /// An entry which needs to go into an `impl` block for a given type.
 struct ImplBlockDetails {
     item: ImplItem,
-    ty: Ident,
+    ty: ImplBlockKey,
 }
 
 struct TraitImplBlockDetails {
@@ -130,10 +137,96 @@
     .to_vec()
 }
 
+fn get_cppref_items() -> Vec<Item> {
+    [
+        Item::Struct(parse_quote! {
+            #[repr(transparent)]
+            pub struct CppRef<'a, T>(pub *const T, pub ::std::marker::PhantomData<&'a T>);
+        }),
+        Item::Impl(parse_quote! {
+            impl<'a, T> autocxx::CppRef<'a, T> for CppRef<'a, T> {
+                fn as_ptr(&self) -> *const T {
+                    self.0
+                }
+            }
+        }),
+        Item::Struct(parse_quote! {
+            #[repr(transparent)]
+            pub struct CppMutRef<'a, T>(pub *mut T, pub ::std::marker::PhantomData<&'a T>);
+        }),
+        Item::Impl(parse_quote! {
+            impl<'a, T> autocxx::CppRef<'a, T> for CppMutRef<'a, T> {
+                fn as_ptr(&self) -> *const T {
+                    self.0
+                }
+            }
+        }),
+        Item::Impl(parse_quote! {
+            impl<'a, T> autocxx::CppMutRef<'a, T> for CppMutRef<'a, T> {
+                fn as_mut_ptr(&self) -> *mut T {
+                    self.0
+                }
+            }
+        }),
+        Item::Impl(parse_quote! {
+            impl<'a, T: ::cxx::private::UniquePtrTarget> CppMutRef<'a, T> {
+                /// Create a const C++ reference from this mutable C++ reference.
+                pub fn as_cpp_ref(&self) -> CppRef<'a, T> {
+                    use autocxx::CppRef;
+                    CppRef(self.as_ptr(), ::std::marker::PhantomData)
+                }
+            }
+        }),
+        Item::Struct(parse_quote! {
+            /// "Pins" a `UniquePtr` to an object, so that C++-compatible references can be created.
+            /// See [`::autocxx::CppPin`]
+            #[repr(transparent)]
+            pub struct CppUniquePtrPin<T: ::cxx::private::UniquePtrTarget>(::cxx::UniquePtr<T>);
+        }),
+        Item::Impl(parse_quote! {
+            impl<'a, T: 'a + ::cxx::private::UniquePtrTarget> autocxx::CppPin<'a, T> for CppUniquePtrPin<T>
+            {
+                type CppRef = CppRef<'a, T>;
+                type CppMutRef = CppMutRef<'a, T>;
+                fn as_ptr(&self) -> *const T {
+                    // TODO add as_ptr to cxx to avoid the ephemeral reference
+                    self.0.as_ref().unwrap() as *const T
+                }
+                fn as_mut_ptr(&mut self) -> *mut T {
+                    unsafe { ::std::pin::Pin::into_inner_unchecked(self.0.as_mut().unwrap()) as *mut T  }
+                }
+                fn as_cpp_ref(&self) -> Self::CppRef {
+                    CppRef(self.as_ptr(), ::std::marker::PhantomData)
+                }
+                fn as_cpp_mut_ref(&mut self) -> Self::CppMutRef {
+                    CppMutRef(self.as_mut_ptr(), ::std::marker::PhantomData)
+                }
+            }
+        }),
+        Item::Impl(parse_quote! {
+            impl<T: ::cxx::private::UniquePtrTarget> CppUniquePtrPin<T> {
+                pub fn new(item: ::cxx::UniquePtr<T>) -> Self {
+                    Self(item)
+                }
+            }
+        }),
+        Item::Fn(parse_quote! {
+            /// Pin this item so that we can create C++ references to it.
+            /// This makes it impossible to hold Rust references because Rust
+            /// references are fundamentally incompatible with C++ references.
+            pub fn cpp_pin_uniqueptr<T: ::cxx::private::UniquePtrTarget> (item: ::cxx::UniquePtr<T>) -> CppUniquePtrPin<T> {
+                CppUniquePtrPin::new(item)
+            }
+        })
+    ]
+    .to_vec()
+}
+
 /// Type which handles generation of Rust code.
 /// In practice, much of the "generation" involves connecting together
 /// existing lumps of code within the Api structures.
 pub(crate) struct RsCodeGenerator<'a> {
+    unsafe_policy: &'a UnsafePolicy,
     include_list: &'a [String],
     bindgen_mod: ItemMod,
     original_name_map: CppNameMap,
@@ -145,12 +238,14 @@
     /// Generate code for a set of APIs that was discovered during parsing.
     pub(crate) fn generate_rs_code(
         all_apis: ApiVec<FnPhase>,
+        unsafe_policy: &'a UnsafePolicy,
         include_list: &'a [String],
         bindgen_mod: ItemMod,
         config: &'a IncludeCppConfig,
         header_name: Option<String>,
     ) -> Vec<Item> {
         let c = Self {
+            unsafe_policy,
             include_list,
             bindgen_mod,
             original_name_map: original_name_map_from_apis(&all_apis),
@@ -219,6 +314,9 @@
         let mut extern_rust_mod_items = extern_rust_mod_items.into_iter().flatten().collect();
         // And a list of global items to include at the top level.
         let mut all_items: Vec<Item> = all_items.into_iter().flatten().collect();
+        if self.config.unsafe_policy.requires_cpprefs() {
+            all_items.append(&mut get_cppref_items())
+        }
         // And finally any C++ we need to generate. And by "we" I mean autocxx not cxx.
         let has_additional_cpp_needs = additional_cpp_needs.into_iter().any(std::convert::identity);
         extern_c_mod_items.extend(self.build_include_foreign_items(has_additional_cpp_needs));
@@ -357,23 +455,24 @@
     }
 
     fn append_uses_for_ns(&mut self, items: &mut Vec<Item>, ns: &Namespace) {
+        let mut imports_from_super = vec!["cxxbridge"];
+        if !self.config.exclude_utilities() {
+            imports_from_super.push("ToCppString");
+        }
+        if self.config.unsafe_policy.requires_cpprefs() {
+            imports_from_super.extend(["CppRef", "CppMutRef"]);
+        }
+        let imports_from_super = imports_from_super.into_iter().map(make_ident);
         let super_duper = std::iter::repeat(make_ident("super")); // I'll get my coat
         let supers = super_duper.clone().take(ns.depth() + 2);
         items.push(Item::Use(parse_quote! {
             #[allow(unused_imports)]
             use self::
                 #(#supers)::*
-            ::cxxbridge;
+            ::{
+                #(#imports_from_super),*
+            };
         }));
-        if !self.config.exclude_utilities() {
-            let supers = super_duper.clone().take(ns.depth() + 2);
-            items.push(Item::Use(parse_quote! {
-                #[allow(unused_imports)]
-                use self::
-                    #(#supers)::*
-                ::ToCppString;
-            }));
-        }
         let supers = super_duper.take(ns.depth() + 1);
         items.push(Item::Use(parse_quote! {
             #[allow(unused_imports)]
@@ -407,8 +506,10 @@
             }
         }
         for (ty, entries) in impl_entries_by_type.into_iter() {
+            let lt = ty.lifetime.map(|lt| quote! { < #lt > });
+            let ty = ty.ty;
             output_items.push(Item::Impl(parse_quote! {
-                impl #ty {
+                impl #lt #ty {
                     #(#entries)*
                 }
             }))
@@ -487,6 +588,7 @@
                 analysis,
                 cpp_call_name,
                 non_pod_types,
+                self.config,
             ),
             Api::Const { const_item, .. } => RsCodegenResult {
                 bindgen_mod_items: vec![Item::Const(const_item)],
@@ -609,8 +711,11 @@
                 name, superclass, ..
             } => {
                 let methods = associated_methods.get(&superclass);
-                let generate_peer_constructor =
-                    subclasses_with_a_single_trivial_constructor.contains(&name.0.name);
+                let generate_peer_constructor = subclasses_with_a_single_trivial_constructor.contains(&name.0.name) &&
+                    // TODO: Create an UnsafeCppPeerConstructor trait for calling an unsafe
+                    // constructor instead? Need to create unsafe versions of everything that uses
+                    // it too.
+                    matches!(self.unsafe_policy, UnsafePolicy::AllFunctionsSafe);
                 self.generate_subclass(name, &superclass, methods, generate_peer_constructor)
             }
             Api::ExternCppType {
@@ -723,6 +828,10 @@
         extern_c_mod_items.push(parse_quote! {
             fn #as_mut_id(self: Pin<&mut #cpp_id>) -> Pin<&mut #super_cxxxbridge_id>;
         });
+        let as_unique_ptr_id = make_ident(format!("{}_As_{}_UniquePtr", cpp_id, super_name));
+        extern_c_mod_items.push(parse_quote! {
+            fn #as_unique_ptr_id(u: UniquePtr<#cpp_id>) -> UniquePtr<#super_cxxxbridge_id>;
+        });
         bindgen_mod_items.push(parse_quote! {
             impl AsRef<#super_path> for super::super::super::#id {
                 fn as_ref(&self) -> &cxxbridge::#super_cxxxbridge_id {
@@ -740,6 +849,14 @@
                 }
             }
         });
+        let rs_as_unique_ptr_id = make_ident(format!("as_{}_unique_ptr", super_name));
+        bindgen_mod_items.push(parse_quote! {
+            impl super::super::super::#id {
+                pub fn #rs_as_unique_ptr_id(u: cxx::UniquePtr<#cpp_id>) -> cxx::UniquePtr<cxxbridge::#super_cxxxbridge_id> {
+                    cxxbridge::#as_unique_ptr_id(u)
+                }
+            }
+        });
         let remove_ownership = sub.remove_ownership();
         global_items.push(parse_quote! {
             #[allow(non_snake_case)]
@@ -813,7 +930,7 @@
                         .as_ref()
                         .#borrow()
                         .expect(#reentrancy_panic_msg);
-                    let r = std::ops::#deref_ty::#deref_call(& #mut_token b);
+                    let r = ::std::ops::#deref_ty::#deref_call(& #mut_token b);
                     #methods_trait :: #method_name
                         (r,
                         #args)
@@ -1012,7 +1129,7 @@
         rust_path: TypePath,
         ns_depth: usize,
     ) -> RsCodegenResult {
-        let id = name.get_final_ident();
+        let id = name.type_path_from_root();
         let super_duper = std::iter::repeat(make_ident("super"));
         let supers = super_duper.take(ns_depth + 2);
         let use_statement = parse_quote! {
@@ -1057,7 +1174,10 @@
                         fn #method(_uhoh: autocxx::BindingGenerationFailure) {
                         }
                     },
-                    ty: self_ty,
+                    ty: ImplBlockKey {
+                        ty: parse_quote! { #self_ty },
+                        lifetime: None,
+                    },
                 })),
                 None,
                 None,
diff --git a/engine/src/conversion/convert_error.rs b/engine/src/conversion/convert_error.rs
index 0de4f19..ba8344d 100644
--- a/engine/src/conversion/convert_error.rs
+++ b/engine/src/conversion/convert_error.rs
@@ -125,6 +125,12 @@
     ConcreteVersionOfIgnoredTemplate,
     #[error("bindgen decided to call this type _bindgen_ty_N because it couldn't deduce the correct name for it. That means we can't generate C++ bindings to it.")]
     BindgenTy,
+    #[error("This is a typedef to a type in an anonymous namespace, not currently supported.")]
+    TypedefToTypeInAnonymousNamespace,
+    #[error("This type refers to a generic type parameter of an outer type, which is not yet supported.")]
+    ReferringToGenericTypeParam,
+    #[error("This forward declaration was nested within another struct/class. autocxx is unable to represent inner types if they are forward declarations.")]
+    ForwardDeclaredNestedType,
 }
 
 /// Ensures that error contexts are always created using the constructors in this
diff --git a/engine/src/conversion/mod.rs b/engine/src/conversion/mod.rs
index 3043dcf..aa639a2 100644
--- a/engine/src/conversion/mod.rs
+++ b/engine/src/conversion/mod.rs
@@ -157,7 +157,7 @@
                 // parameterized by a richer set of metadata.
                 Self::dump_apis("adding casts", &analyzed_apis);
                 let analyzed_apis =
-                    FnAnalyzer::analyze_functions(analyzed_apis, unsafe_policy, self.config);
+                    FnAnalyzer::analyze_functions(analyzed_apis, &unsafe_policy, self.config);
                 // If any of those functions turned out to be pure virtual, don't attempt
                 // to generate UniquePtr implementations for the type, since it can't
                 // be instantiated.
@@ -197,6 +197,7 @@
                 )?;
                 let rs = RsCodeGenerator::generate_rs_code(
                     analyzed_apis,
+                    &unsafe_policy,
                     self.include_list,
                     bindgen_mod,
                     self.config,
diff --git a/engine/src/conversion/parse/bindgen_semantic_attributes.rs b/engine/src/conversion/parse/bindgen_semantic_attributes.rs
index 8b789ae..a8de9ce 100644
--- a/engine/src/conversion/parse/bindgen_semantic_attributes.rs
+++ b/engine/src/conversion/parse/bindgen_semantic_attributes.rs
@@ -61,6 +61,11 @@
                 ConvertError::UnusedTemplateParam,
                 Some(ErrorContext::new_for_item(id_for_context.clone())),
             ))
+        } else if self.get_cpp_visibility() != CppVisibility::Public {
+            Err(ConvertErrorWithContext(
+                ConvertError::NonPublicNestedType,
+                Some(ErrorContext::new_for_item(id_for_context.clone())),
+            ))
         } else {
             Ok(())
         }
diff --git a/engine/src/conversion/parse/parse_bindgen.rs b/engine/src/conversion/parse/parse_bindgen.rs
index 0818aa5..2d4e3de 100644
--- a/engine/src/conversion/parse/parse_bindgen.rs
+++ b/engine/src/conversion/parse/parse_bindgen.rs
@@ -207,7 +207,7 @@
                 // cxx::bridge can't cope with type aliases to generic
                 // types at the moment.
                 let name = api_name_qualified(ns, s.ident.clone(), &annotations)?;
-                let err = annotations.check_for_fatal_attrs(&s.ident).err();
+                let mut err = annotations.check_for_fatal_attrs(&s.ident).err();
                 let api = if ns.is_empty() && self.config.is_rust_type(&s.ident) {
                     None
                 } else if Self::spot_forward_declaration(&s.fields)
@@ -219,6 +219,15 @@
                     // we spot in the previous clause) but instead with an _address field.
                     // So, solely in the case where we're storing up an error about such
                     // a templated type, we'll also treat such cases as forward declarations.
+                    //
+                    // We'll also at this point check for one specific problem with
+                    // forward declarations.
+                    if err.is_none() && name.cpp_name().contains("::") {
+                        err = Some(ConvertErrorWithContext(
+                            ConvertError::ForwardDeclaredNestedType,
+                            Some(ErrorContext::new_for_item(s.ident)),
+                        ));
+                    }
                     Some(UnanalyzedApi::ForwardDeclaration { name, err })
                 } else {
                     let has_rvalue_reference_fields = s.fields.iter().any(|f| {
@@ -227,7 +236,6 @@
                     Some(UnanalyzedApi::Struct {
                         name,
                         details: Box::new(StructDetails {
-                            vis: annotations.get_cpp_visibility(),
                             layout: annotations.get_layout(),
                             item: s,
                             has_rvalue_reference_fields,