autocxx_engine/conversion/codegen_cpp/
mod.rs

1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9mod function_wrapper_cpp;
10mod new_and_delete_prelude;
11pub(crate) mod type_to_cpp;
12
13use crate::{
14    conversion::analysis::fun::{function_wrapper::CppFunctionKind, FnAnalysis},
15    types::QualifiedName,
16    CppCodegenOptions, CppFilePair,
17};
18use autocxx_parser::IncludeCppConfig;
19use indexmap::map::IndexMap as HashMap;
20use indexmap::set::IndexSet as HashSet;
21use itertools::Itertools;
22use std::borrow::Cow;
23use type_to_cpp::CppNameMap;
24
25use super::{
26    analysis::{
27        fun::{
28            function_wrapper::{CppFunction, CppFunctionBody},
29            FnPhase, PodAndDepAnalysis,
30        },
31        pod::PodAnalysis,
32    },
33    api::{Api, Provenance, SubclassName, TypeKind},
34    apivec::ApiVec,
35    ConvertErrorFromCpp, CppEffectiveName,
36};
37
38static GENERATED_FILE_HEADER: &str =
39    "// Generated using autocxx - do not edit directly.\n// @generated.\n\n";
40
41#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
42enum Header {
43    System(&'static str),
44    CxxH,
45    CxxgenH,
46    NewDeletePrelude,
47}
48
49impl Header {
50    fn include_stmt(
51        &self,
52        cpp_codegen_options: &CppCodegenOptions,
53        cxxgen_header_name: &str,
54    ) -> String {
55        let blank = "".to_string();
56        match self {
57            Self::System(name) => format!("#include <{name}>"),
58            Self::CxxH => {
59                let prefix = cpp_codegen_options.path_to_cxx_h.as_ref().unwrap_or(&blank);
60                format!("#include \"{prefix}cxx.h\"")
61            }
62            Self::CxxgenH => {
63                let prefix = cpp_codegen_options
64                    .path_to_cxxgen_h
65                    .as_ref()
66                    .unwrap_or(&blank);
67                format!("#include \"{prefix}{cxxgen_header_name}\"")
68            }
69            Header::NewDeletePrelude => new_and_delete_prelude::NEW_AND_DELETE_PRELUDE.to_string(),
70        }
71    }
72
73    fn is_system(&self) -> bool {
74        matches!(self, Header::System(_) | Header::CxxH)
75    }
76}
77
78enum ConversionDirection {
79    RustCallsCpp,
80    CppCallsCpp,
81    CppCallsRust,
82}
83
84/// Some extra snippet of C++ which we (autocxx) need to generate, beyond
85/// that which cxx itself generates.
86#[derive(Default)]
87struct ExtraCpp {
88    type_definition: Option<String>, // are output before main declarations
89    declaration: Option<String>,
90    definition: Option<String>,
91    headers: Vec<Header>,
92    cpp_headers: Vec<Header>,
93}
94
95/// Generates additional C++ glue functions needed by autocxx.
96/// In some ways it would be preferable to be able to pass snippets
97/// of C++ through to `cxx` for inclusion in the C++ file which it
98/// generates, and perhaps we'll explore that in future. But for now,
99/// autocxx generates its own _additional_ C++ files which therefore
100/// need to be built and included in linking procedures.
101pub(crate) struct CppCodeGenerator<'a> {
102    additional_functions: Vec<ExtraCpp>,
103    inclusions: String,
104    original_name_map: CppNameMap,
105    config: &'a IncludeCppConfig,
106    cpp_codegen_options: &'a CppCodegenOptions<'a>,
107    cxxgen_header_name: &'a str,
108}
109
110struct SubclassFunction<'a> {
111    fun: &'a CppFunction,
112    is_pure_virtual: bool,
113}
114
115impl<'a> CppCodeGenerator<'a> {
116    pub(crate) fn generate_cpp_code(
117        inclusions: String,
118        apis: &ApiVec<FnPhase>,
119        config: &'a IncludeCppConfig,
120        cpp_codegen_options: &CppCodegenOptions,
121        cxxgen_header_name: &str,
122    ) -> Result<Option<CppFilePair>, ConvertErrorFromCpp> {
123        let mut gen = CppCodeGenerator {
124            additional_functions: Vec::new(),
125            inclusions,
126            original_name_map: CppNameMap::new_from_apis(apis),
127            config,
128            cpp_codegen_options,
129            cxxgen_header_name,
130        };
131        // The 'filter' on the following line is designed to ensure we don't accidentally
132        // end up out of sync with needs_cpp_codegen
133        gen.add_needs(apis.iter().filter(|api| api.needs_cpp_codegen()))?;
134        Ok(gen.generate())
135    }
136
137    // It's important to keep this in sync with Api::needs_cpp_codegen.
138    fn add_needs<'b>(
139        &mut self,
140        apis: impl Iterator<Item = &'a Api<FnPhase>>,
141    ) -> Result<(), ConvertErrorFromCpp> {
142        let mut constructors_by_subclass: HashMap<SubclassName, Vec<&CppFunction>> = HashMap::new();
143        let mut methods_by_subclass: HashMap<SubclassName, Vec<SubclassFunction>> = HashMap::new();
144        let mut deferred_apis = Vec::new();
145        for api in apis {
146            match &api {
147                Api::StringConstructor { .. } => self.generate_string_constructor(),
148                Api::Function {
149                    analysis:
150                        FnAnalysis {
151                            cpp_wrapper: Some(cpp_wrapper),
152                            ignore_reason: Ok(_),
153                            externally_callable: true,
154                            ..
155                        },
156                    fun,
157                    ..
158                } => {
159                    if let Provenance::SynthesizedSubclassConstructor(details) = &fun.provenance {
160                        constructors_by_subclass
161                            .entry(details.subclass.clone())
162                            .or_default()
163                            .push(&details.cpp_impl);
164                    }
165                    self.generate_cpp_function(cpp_wrapper)?
166                }
167                Api::ConcreteType {
168                    rs_definition,
169                    cpp_definition,
170                    ..
171                } => {
172                    let effective_cpp_definition = match rs_definition {
173                        Some(rs_definition) => {
174                            Cow::Owned(self.original_name_map.type_to_cpp(rs_definition)?)
175                        }
176                        None => Cow::Borrowed(cpp_definition),
177                    };
178
179                    self.generate_typedef(api.name(), &effective_cpp_definition)
180                }
181                Api::CType { typename, .. } => self.generate_ctype_typedef(typename),
182                Api::Subclass { .. } => deferred_apis.push(api),
183                Api::RustSubclassFn {
184                    subclass, details, ..
185                } => {
186                    methods_by_subclass
187                        .entry(subclass.clone())
188                        .or_default()
189                        .push(SubclassFunction {
190                            fun: &details.cpp_impl,
191                            is_pure_virtual: details.is_pure_virtual,
192                        });
193                }
194                Api::Struct {
195                    name,
196                    analysis:
197                        PodAndDepAnalysis {
198                            pod:
199                                PodAnalysis {
200                                    kind: TypeKind::Pod,
201                                    ..
202                                },
203                            ..
204                        },
205                    ..
206                } => {
207                    self.generate_pod_assertion(name.qualified_cpp_name());
208                }
209                _ => panic!("Should have filtered on needs_cpp_codegen"),
210            }
211        }
212
213        for api in deferred_apis.into_iter() {
214            match api {
215                Api::Subclass { name, superclass } => self.generate_subclass(
216                    superclass,
217                    name,
218                    constructors_by_subclass.remove(name).unwrap_or_default(),
219                    methods_by_subclass.remove(name).unwrap_or_default(),
220                )?,
221                _ => panic!("Unexpected deferred API"),
222            }
223        }
224        Ok(())
225    }
226
227    fn generate(&self) -> Option<CppFilePair> {
228        if self.additional_functions.is_empty() {
229            None
230        } else {
231            let headers = self.collect_headers(|additional_need| &additional_need.headers);
232            let cpp_headers = self.collect_headers(|additional_need| &additional_need.cpp_headers);
233            let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
234            let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
235            let declarations = format!(
236                "{}\n#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
237                GENERATED_FILE_HEADER, headers, self.inclusions, type_definitions, declarations
238            );
239            log::info!("Additional C++ decls:\n{}", declarations);
240            let header_name = self
241                .cpp_codegen_options
242                .autocxxgen_header_namer
243                .name_header(self.config.get_mod_name().to_string());
244            let implementation = if self
245                .additional_functions
246                .iter()
247                .any(|x| x.definition.is_some())
248            {
249                let definitions = self.concat_additional_items(|x| x.definition.as_ref());
250                let definitions =
251                    format!("{GENERATED_FILE_HEADER}\n#include \"{header_name}\"\n{cpp_headers}\n{definitions}");
252                log::info!("Additional C++ defs:\n{}", definitions);
253                Some(definitions.into_bytes())
254            } else {
255                None
256            };
257            Some(CppFilePair {
258                header: declarations.into_bytes(),
259                implementation,
260                header_name,
261            })
262        }
263    }
264
265    fn collect_headers<F>(&self, filter: F) -> String
266    where
267        F: Fn(&ExtraCpp) -> &[Header],
268    {
269        let cpp_headers: HashSet<_> = self
270            .additional_functions
271            .iter()
272            .flat_map(|x| filter(x).iter())
273            .filter(|x| !self.cpp_codegen_options.suppress_system_headers || !x.is_system())
274            .collect(); // uniqify
275        cpp_headers
276            .iter()
277            .map(|x| x.include_stmt(self.cpp_codegen_options, self.cxxgen_header_name))
278            .join("\n")
279    }
280
281    fn concat_additional_items<F>(&self, field_access: F) -> String
282    where
283        F: FnMut(&ExtraCpp) -> Option<&String>,
284    {
285        let mut s = self
286            .additional_functions
287            .iter()
288            .flat_map(field_access)
289            .join("\n");
290        s.push('\n');
291        s
292    }
293
294    fn generate_pod_assertion(&mut self, name: String) {
295        // These assertions are generated by cxx for trivial ExternTypes but
296        // *only if* such types are used as trivial types in the cxx::bridge.
297        // It's possible for types which we generate to be used even without
298        // passing through the cxx::bridge, and as we generate Drop impls, that
299        // can result in destructors for nested types being called multiple times
300        // if we represent them as trivial types. So generate an extra
301        // assertion to make sure.
302        let declaration = Some(format!("static_assert(::rust::IsRelocatable<{name}>::value, \"type {name} should be trivially move constructible and trivially destructible to be used with generate_pod! in autocxx\");"));
303        self.additional_functions.push(ExtraCpp {
304            declaration,
305            headers: vec![Header::CxxH],
306            ..Default::default()
307        })
308    }
309
310    fn generate_string_constructor(&mut self) {
311        let makestring_name = self.config.get_makestring_name();
312        let declaration = Some(format!("inline std::unique_ptr<std::string> {makestring_name}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}"));
313        self.additional_functions.push(ExtraCpp {
314            declaration,
315            headers: vec![
316                Header::System("memory"),
317                Header::System("string"),
318                Header::CxxH,
319            ],
320            ..Default::default()
321        })
322    }
323
324    fn generate_cpp_function(&mut self, details: &CppFunction) -> Result<(), ConvertErrorFromCpp> {
325        self.additional_functions
326            .push(self.generate_cpp_function_inner(
327                details,
328                false,
329                ConversionDirection::RustCallsCpp,
330                false,
331                None,
332            )?);
333        Ok(())
334    }
335
336    fn generate_cpp_function_inner(
337        &self,
338        details: &CppFunction,
339        avoid_this: bool,
340        conversion_direction: ConversionDirection,
341        requires_rust_declarations: bool,
342        force_name: Option<&CppEffectiveName>,
343    ) -> Result<ExtraCpp, ConvertErrorFromCpp> {
344        // Even if the original function call is in a namespace,
345        // we generate this wrapper in the global namespace.
346        // We could easily do this the other way round, and when
347        // cxx::bridge comes to support nested namespace mods then
348        // we wil wish to do that to avoid name conflicts. However,
349        // at the moment this is simpler because it avoids us having
350        // to generate namespace blocks in the generated C++.
351        let is_a_method = !avoid_this
352            && matches!(
353                details.kind,
354                CppFunctionKind::Method
355                    | CppFunctionKind::ConstMethod
356                    | CppFunctionKind::Constructor
357            );
358        let name = match force_name {
359            Some(n) => n.to_string_for_cpp_generation().to_string(),
360            None => details.wrapper_function_name.to_string(),
361        };
362        let get_arg_name = |counter: usize| -> String {
363            if is_a_method && counter == 0 {
364                // For method calls that we generate, the first
365                // argument name needs to be such that we recognize
366                // it as a method in the second invocation of
367                // bridge_converter after it's flowed again through
368                // bindgen.
369                // TODO this may not be the case any longer. We
370                // may be able to remove this.
371                "autocxx_gen_this".to_string()
372            } else {
373                format!("arg{counter}")
374            }
375        };
376        // If this returns a non-POD value, we may instead wish to emplace
377        // it into a parameter, let's see.
378        let args: Result<Vec<_>, _> = details
379            .argument_conversion
380            .iter()
381            .enumerate()
382            .map(|(counter, ty)| {
383                Ok(format!(
384                    "{} {}",
385                    match conversion_direction {
386                        ConversionDirection::RustCallsCpp =>
387                            ty.unconverted_type(&self.original_name_map)?,
388                        ConversionDirection::CppCallsCpp =>
389                            ty.converted_type(&self.original_name_map)?,
390                        ConversionDirection::CppCallsRust =>
391                            ty.inverse().unconverted_type(&self.original_name_map)?,
392                    },
393                    get_arg_name(counter)
394                ))
395            })
396            .collect();
397        let args = args?.join(", ");
398        let default_return = match details.kind {
399            CppFunctionKind::SynthesizedConstructor => "",
400            _ => "void",
401        };
402        let ret_type = details
403            .return_conversion
404            .as_ref()
405            .and_then(|x| match conversion_direction {
406                ConversionDirection::RustCallsCpp => {
407                    if x.populate_return_value() {
408                        Some(x.converted_type(&self.original_name_map))
409                    } else {
410                        None
411                    }
412                }
413                ConversionDirection::CppCallsCpp => {
414                    Some(x.unconverted_type(&self.original_name_map))
415                }
416                ConversionDirection::CppCallsRust => {
417                    Some(x.inverse().converted_type(&self.original_name_map))
418                }
419            })
420            .unwrap_or_else(|| Ok(default_return.to_string()))?;
421        let constness = match details.kind {
422            CppFunctionKind::ConstMethod => " const",
423            _ => "",
424        };
425        let declaration = format!("{ret_type} {name}({args}){constness}");
426        let qualification = if let Some(qualification) = &details.qualification {
427            format!("{}::", qualification.to_cpp_name())
428        } else {
429            "".to_string()
430        };
431        let qualified_declaration = format!("{ret_type} {qualification}{name}({args}){constness}");
432        // Whether there's a placement param in which to put the return value
433        let placement_param = details
434            .argument_conversion
435            .iter()
436            .enumerate()
437            .filter_map(|(counter, conv)| {
438                if conv.is_placement_parameter() {
439                    Some(get_arg_name(counter))
440                } else {
441                    None
442                }
443            })
444            .next();
445        // Arguments to underlying function call
446        let arg_list: Result<Vec<_>, _> = details
447            .argument_conversion
448            .iter()
449            .enumerate()
450            .map(|(counter, conv)| match conversion_direction {
451                ConversionDirection::RustCallsCpp => {
452                    conv.cpp_conversion(&get_arg_name(counter), &self.original_name_map, false)
453                }
454                ConversionDirection::CppCallsCpp => Ok(Some(get_arg_name(counter))),
455                ConversionDirection::CppCallsRust => conv.inverse().cpp_conversion(
456                    &get_arg_name(counter),
457                    &self.original_name_map,
458                    false,
459                ),
460            })
461            .collect();
462        let mut arg_list = arg_list?.into_iter().flatten();
463        let receiver = if is_a_method { arg_list.next() } else { None };
464        if matches!(&details.payload, CppFunctionBody::ConstructSuperclass(_)) {
465            arg_list.next();
466        }
467        let arg_list = if details.pass_obs_field {
468            std::iter::once("*obs".to_string())
469                .chain(arg_list)
470                .join(",")
471        } else {
472            arg_list.join(", ")
473        };
474        let (mut underlying_function_call, field_assignments, need_allocators) = match &details
475            .payload
476        {
477            CppFunctionBody::Cast => (arg_list, "".to_string(), false),
478            CppFunctionBody::PlacementNew(ns, id) => {
479                let ty_id = QualifiedName::new(ns, id.clone());
480                let ty_id = self.namespaced_name(&ty_id);
481                (
482                    format!("new ({}) {}({})", receiver.unwrap(), ty_id, arg_list),
483                    "".to_string(),
484                    false,
485                )
486            }
487            CppFunctionBody::Destructor(ns, id) => {
488                let full_name = QualifiedName::new(ns, id.clone());
489                let ty_id = self.original_name_map.get_final_item(&full_name);
490                let is_a_nested_struct = self.original_name_map.get(&full_name).is_some();
491                // This is all super duper fiddly.
492                // All we want to do is call a destructor. Constraints:
493                // * an unnamed struct, e.g. typedef struct { .. } A, does not
494                //   have any way of fully qualifying its destructor name.
495                //   We have to use a 'using' statement.
496                // * we don't get enough information from bindgen to distinguish
497                //   typedef struct { .. } A  // unnamed struct
498                //   from
499                //   struct A { .. }          // named struct
500                // * we can only do 'using A::B::C' if 'B' is a namespace,
501                //   as opposed to a type with an inner type.
502                // * we can always do 'using C = A::B::C' but then SOME C++
503                //   compilers complain that it's unused, iff it's a named struct.
504                let destructor_call = format!("{arg_list}->{ty_id}::~{ty_id}()");
505                let destructor_call = if ns.is_empty() {
506                    destructor_call
507                } else {
508                    let path = self.original_name_map.map(&full_name);
509                    if is_a_nested_struct {
510                        format!("{{ using {ty_id} = {path}; {destructor_call}; {ty_id}* pointless; (void)pointless; }}")
511                    } else {
512                        format!("{{ using {path}; {destructor_call}; }}")
513                    }
514                };
515                (destructor_call, "".to_string(), false)
516            }
517            CppFunctionBody::FunctionCall(ns, id) => match receiver {
518                Some(receiver) => (
519                    format!(
520                        "{receiver}.{}({arg_list})",
521                        id.to_string_for_cpp_generation()
522                    ),
523                    "".to_string(),
524                    false,
525                ),
526                None => {
527                    let underlying_function_call = ns
528                        .into_iter()
529                        .cloned()
530                        .chain(std::iter::once(
531                            id.to_string_for_cpp_generation().to_string(),
532                        ))
533                        .join("::");
534                    (
535                        format!("{underlying_function_call}({arg_list})"),
536                        "".to_string(),
537                        false,
538                    )
539                }
540            },
541            CppFunctionBody::StaticMethodCall(ns, ty_id, fn_id) => {
542                let underlying_function_call = ns
543                    .into_iter()
544                    .cloned()
545                    .chain(
546                        [
547                            ty_id.to_string(),
548                            fn_id.to_string_for_cpp_generation().to_string(),
549                        ]
550                        .iter()
551                        .cloned(),
552                    )
553                    .join("::");
554                (
555                    format!("{underlying_function_call}({arg_list})"),
556                    "".to_string(),
557                    false,
558                )
559            }
560            CppFunctionBody::ConstructSuperclass(_) => ("".to_string(), arg_list, false),
561            CppFunctionBody::AllocUninitialized(ty) => {
562                let namespaced_ty = self.namespaced_name(ty);
563                (
564                    format!("new_appropriately<{namespaced_ty}>();",),
565                    "".to_string(),
566                    true,
567                )
568            }
569            CppFunctionBody::FreeUninitialized(ty) => (
570                format!("delete_appropriately<{}>(arg0);", self.namespaced_name(ty)),
571                "".to_string(),
572                true,
573            ),
574        };
575        if let Some(ret) = &details.return_conversion {
576            let call_itself = match conversion_direction {
577                ConversionDirection::RustCallsCpp => {
578                    ret.cpp_conversion(&underlying_function_call, &self.original_name_map, true)?
579                }
580                ConversionDirection::CppCallsCpp => Some(underlying_function_call),
581                ConversionDirection::CppCallsRust => ret.inverse().cpp_conversion(
582                    &underlying_function_call,
583                    &self.original_name_map,
584                    true,
585                )?,
586            }
587            .expect(
588                "Expected some conversion type for return value which resulted in a parameter name",
589            );
590
591            underlying_function_call = match placement_param {
592                Some(placement_param) => {
593                    let tyname = self.original_name_map.type_to_cpp(ret.cxxbridge_type())?;
594                    format!("new({placement_param}) {tyname}({call_itself})")
595                }
596                None => format!("return {call_itself}"),
597            };
598        };
599        if !underlying_function_call.is_empty() {
600            underlying_function_call = format!("{underlying_function_call};");
601        }
602        let field_assignments =
603            if let CppFunctionBody::ConstructSuperclass(superclass_name) = &details.payload {
604                let superclass_assignments = if field_assignments.is_empty() {
605                    "".to_string()
606                } else {
607                    format!("{superclass_name}({field_assignments}), ")
608                };
609                format!(": {superclass_assignments}obs(std::move(arg0))")
610            } else {
611                "".into()
612            };
613        let definition_after_sig = format!("{field_assignments} {{ {underlying_function_call} }}",);
614        let (declaration, definition) = if requires_rust_declarations {
615            (
616                Some(format!("{declaration};")),
617                Some(format!("{qualified_declaration} {definition_after_sig}")),
618            )
619        } else {
620            (
621                Some(format!("inline {declaration} {definition_after_sig}")),
622                None,
623            )
624        };
625        let mut headers = vec![Header::System("memory")];
626        if need_allocators {
627            headers.push(Header::System("stddef.h"));
628            headers.push(Header::NewDeletePrelude);
629        }
630        Ok(ExtraCpp {
631            declaration,
632            definition,
633            headers,
634            ..Default::default()
635        })
636    }
637
638    fn namespaced_name(&self, name: &QualifiedName) -> String {
639        self.original_name_map.map(name)
640    }
641
642    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
643        let cpp_name = tn.to_cpp_name();
644        self.generate_typedef(tn, &cpp_name)
645    }
646
647    fn generate_typedef(&mut self, tn: &QualifiedName, definition: &str) {
648        let our_name = tn.get_final_item();
649        self.additional_functions.push(ExtraCpp {
650            type_definition: Some(format!("typedef {definition} {our_name};")),
651            ..Default::default()
652        })
653    }
654
655    fn generate_subclass(
656        &mut self,
657        superclass: &QualifiedName,
658        subclass: &SubclassName,
659        constructors: Vec<&CppFunction>,
660        methods: Vec<SubclassFunction>,
661    ) -> Result<(), ConvertErrorFromCpp> {
662        let holder = subclass.holder();
663        self.additional_functions.push(ExtraCpp {
664            type_definition: Some(format!("struct {holder};")),
665            ..Default::default()
666        });
667        let mut method_decls = Vec::new();
668        for method in methods {
669            // First the method which calls from C++ to Rust
670            let mut fn_impl = self.generate_cpp_function_inner(
671                method.fun,
672                true,
673                ConversionDirection::CppCallsRust,
674                true,
675                Some(&method.fun.original_cpp_name),
676            )?;
677            method_decls.push(fn_impl.declaration.take().unwrap());
678            self.additional_functions.push(fn_impl);
679            // And now the function to be called from Rust for default implementation (calls superclass in C++)
680            if !method.is_pure_virtual {
681                let mut super_method = method.fun.clone();
682                super_method.pass_obs_field = false;
683                super_method.wrapper_function_name = SubclassName::get_super_fn_name(
684                    superclass.get_namespace(),
685                    &method.fun.wrapper_function_name.to_string(),
686                )
687                .get_final_ident();
688                super_method.payload = CppFunctionBody::StaticMethodCall(
689                    superclass.get_namespace().clone(),
690                    superclass.get_final_ident(),
691                    method.fun.original_cpp_name.clone(),
692                );
693                let mut super_fn_impl = self.generate_cpp_function_inner(
694                    &super_method,
695                    true,
696                    ConversionDirection::CppCallsCpp,
697                    false,
698                    None,
699                )?;
700                method_decls.push(super_fn_impl.declaration.take().unwrap());
701                self.additional_functions.push(super_fn_impl);
702            }
703        }
704        // In future, for each superclass..
705        let super_name = superclass.get_final_item();
706        method_decls.push(format!(
707            "const {super_name}& As_{super_name}() const {{ return *this; }}",
708        ));
709        method_decls.push(format!(
710            "{super_name}& As_{super_name}_mut() {{ return *this; }}"
711        ));
712        self.additional_functions.push(ExtraCpp {
713            declaration: Some(format!(
714                "inline std::unique_ptr<{}> {}_As_{}_UniquePtr(std::unique_ptr<{}> u) {{ return std::unique_ptr<{}>(u.release()); }}",
715                superclass.to_cpp_name(), subclass.cpp(), super_name, subclass.cpp(), superclass.to_cpp_name(),
716                )),
717                ..Default::default()
718        });
719        // And now constructors
720        let mut constructor_decls: Vec<String> = Vec::new();
721        for constructor in constructors {
722            let mut fn_impl = self.generate_cpp_function_inner(
723                constructor,
724                false,
725                ConversionDirection::CppCallsCpp,
726                false,
727                None,
728            )?;
729            let decl = fn_impl.declaration.take().unwrap();
730            constructor_decls.push(decl);
731            self.additional_functions.push(fn_impl);
732        }
733        self.additional_functions.push(ExtraCpp {
734            type_definition: Some(format!(
735                "class {} : public {}\n{{\npublic:\n{}\n{}\nvoid {}() const;\nprivate:rust::Box<{}> obs;\nvoid really_remove_ownership();\n\n}};",
736                subclass.cpp(),
737                superclass.to_cpp_name(),
738                constructor_decls.join("\n"),
739                method_decls.join("\n"),
740                subclass.cpp_remove_ownership(),
741                holder
742            )),
743            definition: Some(format!(
744                "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",
745                subclass.cpp(),
746                subclass.cpp_remove_ownership(),
747                subclass.cpp(),
748                subclass.cpp(),
749                subclass.remove_ownership()
750            )),
751            cpp_headers: vec![Header::CxxgenH],
752            ..Default::default()
753        });
754        Ok(())
755    }
756}