Squashed 'third_party/autocxx/' content from commit 629e8fa53

git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/engine/src/conversion/codegen_cpp/mod.rs b/engine/src/conversion/codegen_cpp/mod.rs
new file mode 100644
index 0000000..02e92b2
--- /dev/null
+++ b/engine/src/conversion/codegen_cpp/mod.rs
@@ -0,0 +1,724 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod function_wrapper_cpp;
+mod new_and_delete_prelude;
+pub(crate) mod type_to_cpp;
+
+use crate::{
+    conversion::analysis::fun::{function_wrapper::CppFunctionKind, FnAnalysis},
+    types::{make_ident, QualifiedName},
+    CppCodegenOptions, CppFilePair,
+};
+use autocxx_parser::IncludeCppConfig;
+use indexmap::map::IndexMap as HashMap;
+use indexmap::set::IndexSet as HashSet;
+use itertools::Itertools;
+use std::borrow::Cow;
+use type_to_cpp::{original_name_map_from_apis, type_to_cpp, CppNameMap};
+
+use self::type_to_cpp::{
+    final_ident_using_original_name_map, namespaced_name_using_original_name_map,
+};
+
+use super::{
+    analysis::{
+        fun::{
+            function_wrapper::{CppFunction, CppFunctionBody},
+            FnPhase, PodAndDepAnalysis,
+        },
+        pod::PodAnalysis,
+    },
+    api::{Api, Provenance, SubclassName, TypeKind},
+    apivec::ApiVec,
+    ConvertError,
+};
+
+#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
+enum Header {
+    System(&'static str),
+    CxxH,
+    CxxgenH,
+    NewDeletePrelude,
+}
+
+impl Header {
+    fn include_stmt(
+        &self,
+        cpp_codegen_options: &CppCodegenOptions,
+        cxxgen_header_name: &str,
+    ) -> String {
+        let blank = "".to_string();
+        match self {
+            Self::System(name) => format!("#include <{}>", name),
+            Self::CxxH => {
+                let prefix = cpp_codegen_options.path_to_cxx_h.as_ref().unwrap_or(&blank);
+                format!("#include \"{}cxx.h\"", prefix)
+            }
+            Self::CxxgenH => {
+                let prefix = cpp_codegen_options
+                    .path_to_cxxgen_h
+                    .as_ref()
+                    .unwrap_or(&blank);
+                format!("#include \"{}{}\"", prefix, cxxgen_header_name)
+            }
+            Header::NewDeletePrelude => new_and_delete_prelude::NEW_AND_DELETE_PRELUDE.to_string(),
+        }
+    }
+
+    fn is_system(&self) -> bool {
+        matches!(self, Header::System(_) | Header::CxxH)
+    }
+}
+
+enum ConversionDirection {
+    RustCallsCpp,
+    CppCallsCpp,
+    CppCallsRust,
+}
+
+/// Some extra snippet of C++ which we (autocxx) need to generate, beyond
+/// that which cxx itself generates.
+#[derive(Default)]
+struct ExtraCpp {
+    type_definition: Option<String>, // are output before main declarations
+    declaration: Option<String>,
+    definition: Option<String>,
+    headers: Vec<Header>,
+    cpp_headers: Vec<Header>,
+}
+
+/// Generates additional C++ glue functions needed by autocxx.
+/// In some ways it would be preferable to be able to pass snippets
+/// of C++ through to `cxx` for inclusion in the C++ file which it
+/// generates, and perhaps we'll explore that in future. But for now,
+/// autocxx generates its own _additional_ C++ files which therefore
+/// need to be built and included in linking procedures.
+pub(crate) struct CppCodeGenerator<'a> {
+    additional_functions: Vec<ExtraCpp>,
+    inclusions: String,
+    original_name_map: CppNameMap,
+    config: &'a IncludeCppConfig,
+    cpp_codegen_options: &'a CppCodegenOptions<'a>,
+    cxxgen_header_name: &'a str,
+}
+
+struct SubclassFunction<'a> {
+    fun: &'a CppFunction,
+    is_pure_virtual: bool,
+}
+
+impl<'a> CppCodeGenerator<'a> {
+    pub(crate) fn generate_cpp_code(
+        inclusions: String,
+        apis: &ApiVec<FnPhase>,
+        config: &'a IncludeCppConfig,
+        cpp_codegen_options: &CppCodegenOptions,
+        cxxgen_header_name: &str,
+    ) -> Result<Option<CppFilePair>, ConvertError> {
+        let mut gen = CppCodeGenerator {
+            additional_functions: Vec::new(),
+            inclusions,
+            original_name_map: original_name_map_from_apis(apis),
+            config,
+            cpp_codegen_options,
+            cxxgen_header_name,
+        };
+        // The 'filter' on the following line is designed to ensure we don't accidentally
+        // end up out of sync with needs_cpp_codegen
+        gen.add_needs(apis.iter().filter(|api| api.needs_cpp_codegen()))?;
+        Ok(gen.generate())
+    }
+
+    // It's important to keep this in sync with Api::needs_cpp_codegen.
+    fn add_needs<'b>(
+        &mut self,
+        apis: impl Iterator<Item = &'a Api<FnPhase>>,
+    ) -> Result<(), ConvertError> {
+        let mut constructors_by_subclass: HashMap<SubclassName, Vec<&CppFunction>> = HashMap::new();
+        let mut methods_by_subclass: HashMap<SubclassName, Vec<SubclassFunction>> = HashMap::new();
+        let mut deferred_apis = Vec::new();
+        for api in apis {
+            match &api {
+                Api::StringConstructor { .. } => self.generate_string_constructor(),
+                Api::Function {
+                    analysis:
+                        FnAnalysis {
+                            cpp_wrapper: Some(cpp_wrapper),
+                            ignore_reason: Ok(_),
+                            externally_callable: true,
+                            ..
+                        },
+                    fun,
+                    ..
+                } => {
+                    if let Provenance::SynthesizedSubclassConstructor(details) = &fun.provenance {
+                        constructors_by_subclass
+                            .entry(details.subclass.clone())
+                            .or_default()
+                            .push(&details.cpp_impl);
+                    }
+                    self.generate_cpp_function(cpp_wrapper)?
+                }
+                Api::ConcreteType {
+                    rs_definition,
+                    cpp_definition,
+                    ..
+                } => {
+                    let effective_cpp_definition = match rs_definition {
+                        Some(rs_definition) => {
+                            Cow::Owned(type_to_cpp(rs_definition, &self.original_name_map)?)
+                        }
+                        None => Cow::Borrowed(cpp_definition),
+                    };
+
+                    self.generate_typedef(api.name(), &effective_cpp_definition)
+                }
+                Api::CType { typename, .. } => self.generate_ctype_typedef(typename),
+                Api::Subclass { .. } => deferred_apis.push(api),
+                Api::RustSubclassFn {
+                    subclass, details, ..
+                } => {
+                    methods_by_subclass
+                        .entry(subclass.clone())
+                        .or_default()
+                        .push(SubclassFunction {
+                            fun: &details.cpp_impl,
+                            is_pure_virtual: details.is_pure_virtual,
+                        });
+                }
+                Api::Struct {
+                    name,
+                    analysis:
+                        PodAndDepAnalysis {
+                            pod:
+                                PodAnalysis {
+                                    kind: TypeKind::Pod,
+                                    ..
+                                },
+                            ..
+                        },
+                    ..
+                } => {
+                    self.generate_pod_assertion(name.qualified_cpp_name());
+                }
+                _ => panic!("Should have filtered on needs_cpp_codegen"),
+            }
+        }
+
+        for api in deferred_apis.into_iter() {
+            match api {
+                Api::Subclass { name, superclass } => self.generate_subclass(
+                    superclass,
+                    name,
+                    constructors_by_subclass.remove(name).unwrap_or_default(),
+                    methods_by_subclass.remove(name).unwrap_or_default(),
+                )?,
+                _ => panic!("Unexpected deferred API"),
+            }
+        }
+        Ok(())
+    }
+
+    fn generate(&self) -> Option<CppFilePair> {
+        if self.additional_functions.is_empty() {
+            None
+        } else {
+            let headers = self.collect_headers(|additional_need| &additional_need.headers);
+            let cpp_headers = self.collect_headers(|additional_need| &additional_need.cpp_headers);
+            let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
+            let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
+            let declarations = format!(
+                "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
+                headers, self.inclusions, type_definitions, declarations
+            );
+            log::info!("Additional C++ decls:\n{}", declarations);
+            let header_name = self
+                .cpp_codegen_options
+                .autocxxgen_header_namer
+                .name_header(self.config.get_mod_name().to_string());
+            let implementation = if self
+                .additional_functions
+                .iter()
+                .any(|x| x.definition.is_some())
+            {
+                let definitions = self.concat_additional_items(|x| x.definition.as_ref());
+                let definitions = format!(
+                    "#include \"{}\"\n{}\n{}",
+                    header_name, cpp_headers, definitions
+                );
+                log::info!("Additional C++ defs:\n{}", definitions);
+                Some(definitions.into_bytes())
+            } else {
+                None
+            };
+            Some(CppFilePair {
+                header: declarations.into_bytes(),
+                implementation,
+                header_name,
+            })
+        }
+    }
+
+    fn collect_headers<F>(&self, filter: F) -> String
+    where
+        F: Fn(&ExtraCpp) -> &[Header],
+    {
+        let cpp_headers: HashSet<_> = self
+            .additional_functions
+            .iter()
+            .flat_map(|x| filter(x).iter())
+            .filter(|x| !self.cpp_codegen_options.suppress_system_headers || !x.is_system())
+            .collect(); // uniqify
+        cpp_headers
+            .iter()
+            .map(|x| x.include_stmt(self.cpp_codegen_options, self.cxxgen_header_name))
+            .join("\n")
+    }
+
+    fn concat_additional_items<F>(&self, field_access: F) -> String
+    where
+        F: FnMut(&ExtraCpp) -> Option<&String>,
+    {
+        let mut s = self
+            .additional_functions
+            .iter()
+            .flat_map(field_access)
+            .join("\n");
+        s.push('\n');
+        s
+    }
+
+    fn generate_pod_assertion(&mut self, name: String) {
+        // These assertions are generated by cxx for trivial ExternTypes but
+        // *only if* such types are used as trivial types in the cxx::bridge.
+        // It's possible for types which we generate to be used even without
+        // passing through the cxx::bridge, and as we generate Drop impls, that
+        // can result in destructors for nested types being called multiple times
+        // if we represent them as trivial types. So generate an extra
+        // assertion to make sure.
+        let declaration = Some(format!("static_assert(::rust::IsRelocatable<{}>::value, \"type {} should be trivially move constructible and trivially destructible to be used with generate_pod! in autocxx\");", name, name));
+        self.additional_functions.push(ExtraCpp {
+            declaration,
+            headers: vec![Header::CxxH],
+            ..Default::default()
+        })
+    }
+
+    fn generate_string_constructor(&mut self) {
+        let makestring_name = self.config.get_makestring_name();
+        let declaration = Some(format!("inline std::unique_ptr<std::string> {}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}", makestring_name));
+        self.additional_functions.push(ExtraCpp {
+            declaration,
+            headers: vec![
+                Header::System("memory"),
+                Header::System("string"),
+                Header::CxxH,
+            ],
+            ..Default::default()
+        })
+    }
+
+    fn generate_cpp_function(&mut self, details: &CppFunction) -> Result<(), ConvertError> {
+        self.additional_functions
+            .push(self.generate_cpp_function_inner(
+                details,
+                false,
+                ConversionDirection::RustCallsCpp,
+                false,
+                None,
+            )?);
+        Ok(())
+    }
+
+    fn generate_cpp_function_inner(
+        &self,
+        details: &CppFunction,
+        avoid_this: bool,
+        conversion_direction: ConversionDirection,
+        requires_rust_declarations: bool,
+        force_name: Option<&str>,
+    ) -> Result<ExtraCpp, ConvertError> {
+        // Even if the original function call is in a namespace,
+        // we generate this wrapper in the global namespace.
+        // We could easily do this the other way round, and when
+        // cxx::bridge comes to support nested namespace mods then
+        // we wil wish to do that to avoid name conflicts. However,
+        // at the moment this is simpler because it avoids us having
+        // to generate namespace blocks in the generated C++.
+        let is_a_method = !avoid_this
+            && matches!(
+                details.kind,
+                CppFunctionKind::Method
+                    | CppFunctionKind::ConstMethod
+                    | CppFunctionKind::Constructor
+            );
+        let name = match force_name {
+            Some(n) => n.to_string(),
+            None => details.wrapper_function_name.to_string(),
+        };
+        let get_arg_name = |counter: usize| -> String {
+            if is_a_method && counter == 0 {
+                // For method calls that we generate, the first
+                // argument name needs to be such that we recognize
+                // it as a method in the second invocation of
+                // bridge_converter after it's flowed again through
+                // bindgen.
+                // TODO this may not be the case any longer. We
+                // may be able to remove this.
+                "autocxx_gen_this".to_string()
+            } else {
+                format!("arg{}", counter)
+            }
+        };
+        // If this returns a non-POD value, we may instead wish to emplace
+        // it into a parameter, let's see.
+        let args: Result<Vec<_>, _> = details
+            .argument_conversion
+            .iter()
+            .enumerate()
+            .map(|(counter, ty)| {
+                Ok(format!(
+                    "{} {}",
+                    match conversion_direction {
+                        ConversionDirection::RustCallsCpp =>
+                            ty.unconverted_type(&self.original_name_map)?,
+                        ConversionDirection::CppCallsCpp =>
+                            ty.converted_type(&self.original_name_map)?,
+                        ConversionDirection::CppCallsRust =>
+                            ty.inverse().unconverted_type(&self.original_name_map)?,
+                    },
+                    get_arg_name(counter)
+                ))
+            })
+            .collect();
+        let args = args?.join(", ");
+        let default_return = match details.kind {
+            CppFunctionKind::SynthesizedConstructor => "",
+            _ => "void",
+        };
+        let ret_type = details
+            .return_conversion
+            .as_ref()
+            .and_then(|x| match conversion_direction {
+                ConversionDirection::RustCallsCpp => {
+                    if x.populate_return_value() {
+                        Some(x.converted_type(&self.original_name_map))
+                    } else {
+                        None
+                    }
+                }
+                ConversionDirection::CppCallsCpp => {
+                    Some(x.unconverted_type(&self.original_name_map))
+                }
+                ConversionDirection::CppCallsRust => {
+                    Some(x.inverse().converted_type(&self.original_name_map))
+                }
+            })
+            .unwrap_or_else(|| Ok(default_return.to_string()))?;
+        let constness = match details.kind {
+            CppFunctionKind::ConstMethod => " const",
+            _ => "",
+        };
+        let declaration = format!("{} {}({}){}", ret_type, name, args, constness);
+        let qualification = if let Some(qualification) = &details.qualification {
+            format!("{}::", qualification.to_cpp_name())
+        } else {
+            "".to_string()
+        };
+        let qualified_declaration = format!(
+            "{} {}{}({}){}",
+            ret_type, qualification, name, args, constness
+        );
+        // Whether there's a placement param in which to put the return value
+        let placement_param = details
+            .argument_conversion
+            .iter()
+            .enumerate()
+            .filter_map(|(counter, conv)| {
+                if conv.is_placement_parameter() {
+                    Some(get_arg_name(counter))
+                } else {
+                    None
+                }
+            })
+            .next();
+        // Arguments to underlying function call
+        let arg_list: Result<Vec<_>, _> = details
+            .argument_conversion
+            .iter()
+            .enumerate()
+            .map(|(counter, conv)| match conversion_direction {
+                ConversionDirection::RustCallsCpp => {
+                    conv.cpp_conversion(&get_arg_name(counter), &self.original_name_map, false)
+                }
+                ConversionDirection::CppCallsCpp => Ok(Some(get_arg_name(counter))),
+                ConversionDirection::CppCallsRust => conv.inverse().cpp_conversion(
+                    &get_arg_name(counter),
+                    &self.original_name_map,
+                    false,
+                ),
+            })
+            .collect();
+        let mut arg_list = arg_list?.into_iter().flatten();
+        let receiver = if is_a_method { arg_list.next() } else { None };
+        if matches!(&details.payload, CppFunctionBody::ConstructSuperclass(_)) {
+            arg_list.next();
+        }
+        let arg_list = if details.pass_obs_field {
+            std::iter::once("*obs".to_string())
+                .chain(arg_list)
+                .join(",")
+        } else {
+            arg_list.join(", ")
+        };
+        let (mut underlying_function_call, field_assignments, need_allocators) = match &details
+            .payload
+        {
+            CppFunctionBody::Cast => (arg_list, "".to_string(), false),
+            CppFunctionBody::PlacementNew(ns, id) => {
+                let ty_id = QualifiedName::new(ns, id.clone());
+                let ty_id = self.namespaced_name(&ty_id);
+                (
+                    format!("new ({}) {}({})", receiver.unwrap(), ty_id, arg_list),
+                    "".to_string(),
+                    false,
+                )
+            }
+            CppFunctionBody::Destructor(ns, id) => {
+                let ty_id = QualifiedName::new(ns, id.clone());
+                let ty_id = final_ident_using_original_name_map(&ty_id, &self.original_name_map);
+                (format!("{}->~{}()", arg_list, ty_id), "".to_string(), false)
+            }
+            CppFunctionBody::FunctionCall(ns, id) => match receiver {
+                Some(receiver) => (
+                    format!("{}.{}({})", receiver, id, arg_list),
+                    "".to_string(),
+                    false,
+                ),
+                None => {
+                    let underlying_function_call = ns
+                        .into_iter()
+                        .cloned()
+                        .chain(std::iter::once(id.to_string()))
+                        .join("::");
+                    (
+                        format!("{}({})", underlying_function_call, arg_list),
+                        "".to_string(),
+                        false,
+                    )
+                }
+            },
+            CppFunctionBody::StaticMethodCall(ns, ty_id, fn_id) => {
+                let underlying_function_call = ns
+                    .into_iter()
+                    .cloned()
+                    .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
+                    .join("::");
+                (
+                    format!("{}({})", underlying_function_call, arg_list),
+                    "".to_string(),
+                    false,
+                )
+            }
+            CppFunctionBody::ConstructSuperclass(_) => ("".to_string(), arg_list, false),
+            CppFunctionBody::AllocUninitialized(ty) => {
+                let namespaced_ty = self.namespaced_name(ty);
+                (
+                    format!("new_appropriately<{}>();", namespaced_ty,),
+                    "".to_string(),
+                    true,
+                )
+            }
+            CppFunctionBody::FreeUninitialized(ty) => (
+                format!("delete_appropriately<{}>(arg0);", self.namespaced_name(ty)),
+                "".to_string(),
+                true,
+            ),
+        };
+        if let Some(ret) = &details.return_conversion {
+            let call_itself = match conversion_direction {
+                ConversionDirection::RustCallsCpp => {
+                    ret.cpp_conversion(&underlying_function_call, &self.original_name_map, true)?
+                }
+                ConversionDirection::CppCallsCpp => Some(underlying_function_call),
+                ConversionDirection::CppCallsRust => ret.inverse().cpp_conversion(
+                    &underlying_function_call,
+                    &self.original_name_map,
+                    true,
+                )?,
+            }
+            .expect(
+                "Expected some conversion type for return value which resulted in a parameter name",
+            );
+
+            underlying_function_call = match placement_param {
+                Some(placement_param) => {
+                    let tyname = type_to_cpp(&ret.unwrapped_type, &self.original_name_map)?;
+                    format!("new({}) {}({})", placement_param, tyname, call_itself)
+                }
+                None => format!("return {}", call_itself),
+            };
+        };
+        if !underlying_function_call.is_empty() {
+            underlying_function_call = format!("{};", underlying_function_call);
+        }
+        let field_assignments =
+            if let CppFunctionBody::ConstructSuperclass(superclass_name) = &details.payload {
+                let superclass_assignments = if field_assignments.is_empty() {
+                    "".to_string()
+                } else {
+                    format!("{}({}), ", superclass_name, field_assignments)
+                };
+                format!(": {}obs(std::move(arg0))", superclass_assignments)
+            } else {
+                "".into()
+            };
+        let definition_after_sig =
+            format!("{} {{ {} }}", field_assignments, underlying_function_call,);
+        let (declaration, definition) = if requires_rust_declarations {
+            (
+                Some(format!("{};", declaration)),
+                Some(format!(
+                    "{} {}",
+                    qualified_declaration, definition_after_sig
+                )),
+            )
+        } else {
+            (
+                Some(format!("inline {} {}", declaration, definition_after_sig)),
+                None,
+            )
+        };
+        let mut headers = vec![Header::System("memory")];
+        if need_allocators {
+            headers.push(Header::System("stddef.h"));
+            headers.push(Header::NewDeletePrelude);
+        }
+        Ok(ExtraCpp {
+            declaration,
+            definition,
+            headers,
+            ..Default::default()
+        })
+    }
+
+    fn namespaced_name(&self, name: &QualifiedName) -> String {
+        namespaced_name_using_original_name_map(name, &self.original_name_map)
+    }
+
+    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
+        let cpp_name = tn.to_cpp_name();
+        self.generate_typedef(tn, &cpp_name)
+    }
+
+    fn generate_typedef(&mut self, tn: &QualifiedName, definition: &str) {
+        let our_name = tn.get_final_item();
+        self.additional_functions.push(ExtraCpp {
+            type_definition: Some(format!("typedef {} {};", definition, our_name)),
+            ..Default::default()
+        })
+    }
+
+    fn generate_subclass(
+        &mut self,
+        superclass: &QualifiedName,
+        subclass: &SubclassName,
+        constructors: Vec<&CppFunction>,
+        methods: Vec<SubclassFunction>,
+    ) -> Result<(), ConvertError> {
+        let holder = subclass.holder();
+        self.additional_functions.push(ExtraCpp {
+            type_definition: Some(format!("struct {};", holder)),
+            ..Default::default()
+        });
+        let mut method_decls = Vec::new();
+        for method in methods {
+            // First the method which calls from C++ to Rust
+            let mut fn_impl = self.generate_cpp_function_inner(
+                method.fun,
+                true,
+                ConversionDirection::CppCallsRust,
+                true,
+                Some(&method.fun.original_cpp_name),
+            )?;
+            method_decls.push(fn_impl.declaration.take().unwrap());
+            self.additional_functions.push(fn_impl);
+            // And now the function to be called from Rust for default implementation (calls superclass in C++)
+            if !method.is_pure_virtual {
+                let mut super_method = method.fun.clone();
+                super_method.pass_obs_field = false;
+                super_method.wrapper_function_name = SubclassName::get_super_fn_name(
+                    superclass.get_namespace(),
+                    &method.fun.wrapper_function_name.to_string(),
+                )
+                .get_final_ident();
+                super_method.payload = CppFunctionBody::StaticMethodCall(
+                    superclass.get_namespace().clone(),
+                    superclass.get_final_ident(),
+                    make_ident(&method.fun.original_cpp_name),
+                );
+                let mut super_fn_impl = self.generate_cpp_function_inner(
+                    &super_method,
+                    true,
+                    ConversionDirection::CppCallsCpp,
+                    false,
+                    None,
+                )?;
+                method_decls.push(super_fn_impl.declaration.take().unwrap());
+                self.additional_functions.push(super_fn_impl);
+            }
+        }
+        // In future, for each superclass..
+        let super_name = superclass.get_final_item();
+        method_decls.push(format!(
+            "const {}& As_{}() const {{ return *this; }}",
+            super_name, super_name,
+        ));
+        method_decls.push(format!(
+            "{}& As_{}_mut() {{ return *this; }}",
+            super_name, super_name
+        ));
+        // And now constructors
+        let mut constructor_decls: Vec<String> = Vec::new();
+        for constructor in constructors {
+            let mut fn_impl = self.generate_cpp_function_inner(
+                constructor,
+                false,
+                ConversionDirection::CppCallsCpp,
+                false,
+                None,
+            )?;
+            let decl = fn_impl.declaration.take().unwrap();
+            constructor_decls.push(decl);
+            self.additional_functions.push(fn_impl);
+        }
+        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}};",
+                subclass.cpp(),
+                superclass.to_cpp_name(),
+                constructor_decls.join("\n"),
+                method_decls.join("\n"),
+                subclass.cpp_remove_ownership(),
+                holder
+            )),
+            definition: Some(format!(
+                "void {}::{}() const {{\nconst_cast<{}*>(this)->really_remove_ownership();\n}}\nvoid {}::really_remove_ownership() {{\nauto new_obs = {}(std::move(obs));\nobs = std::move(new_obs);\n}}\n",
+                subclass.cpp(),
+                subclass.cpp_remove_ownership(),
+                subclass.cpp(),
+                subclass.cpp(),
+                subclass.remove_ownership()
+            )),
+            cpp_headers: vec![Header::CxxgenH],
+            ..Default::default()
+        });
+        Ok(())
+    }
+}