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/integration-tests/tests/builder_modifiers.rs b/integration-tests/tests/builder_modifiers.rs
new file mode 100644
index 0000000..0cf763e
--- /dev/null
+++ b/integration-tests/tests/builder_modifiers.rs
@@ -0,0 +1,61 @@
+// Copyright 2021 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.
+
+use autocxx_engine::Builder;
+
+use autocxx_integration_tests::{BuilderModifier, BuilderModifierFns, TestBuilderContext};
+
+pub(crate) fn make_cpp17_adder() -> Option<BuilderModifier> {
+    make_clang_arg_adder(&["-std=c++17"])
+}
+
+struct ClangArgAdder(Vec<String>);
+
+pub(crate) fn make_clang_arg_adder(args: &[&str]) -> Option<BuilderModifier> {
+    let args: Vec<_> = args.iter().map(|a| a.to_string()).collect();
+    Some(Box::new(ClangArgAdder(args)))
+}
+
+impl BuilderModifierFns for ClangArgAdder {
+    fn modify_autocxx_builder<'a>(
+        &self,
+        builder: Builder<'a, TestBuilderContext>,
+    ) -> Builder<'a, TestBuilderContext> {
+        let refs: Vec<_> = self.0.iter().map(|s| s.as_str()).collect();
+        builder.extra_clang_args(&refs)
+    }
+
+    fn modify_cc_builder<'a>(&self, mut builder: &'a mut cc::Build) -> &'a mut cc::Build {
+        for f in &self.0 {
+            builder = builder.flag(f);
+        }
+        builder
+    }
+}
+
+pub(crate) struct SetSuppressSystemHeaders;
+
+impl BuilderModifierFns for SetSuppressSystemHeaders {
+    fn modify_autocxx_builder<'a>(
+        &self,
+        builder: Builder<'a, TestBuilderContext>,
+    ) -> Builder<'a, TestBuilderContext> {
+        builder.suppress_system_headers(true)
+    }
+}
+
+pub(crate) struct EnableAutodiscover;
+
+impl BuilderModifierFns for EnableAutodiscover {
+    fn modify_autocxx_builder<'a>(
+        &self,
+        builder: Builder<'a, TestBuilderContext>,
+    ) -> Builder<'a, TestBuilderContext> {
+        builder.auto_allowlist(true)
+    }
+}
diff --git a/integration-tests/tests/code_checkers.rs b/integration-tests/tests/code_checkers.rs
new file mode 100644
index 0000000..619c79c
--- /dev/null
+++ b/integration-tests/tests/code_checkers.rs
@@ -0,0 +1,182 @@
+// Copyright 2021 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.
+
+use std::{
+    fs::File,
+    io::{BufRead, BufReader},
+    path::PathBuf,
+};
+
+use itertools::{Either, Itertools};
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::Item;
+
+use autocxx_integration_tests::{CodeChecker, CodeCheckerFns, TestError};
+
+/// Generates a closure which can be used to ensure that the given symbol
+/// is mentioned in the output and has documentation attached.
+/// The idea is that this is what we do in cases where we can't generate code properly.
+pub(crate) fn make_error_finder(error_symbol: &'static str) -> CodeChecker {
+    Box::new(ErrorFinder(error_symbol))
+}
+struct ErrorFinder(&'static str);
+
+impl CodeCheckerFns for ErrorFinder {
+    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
+        let ffi_items = find_ffi_items(rs)?;
+        // Ensure there's some kind of struct entry for this symbol
+        let error_item = ffi_items
+            .into_iter()
+            .filter_map(|i| match i {
+                Item::Struct(its) if its.ident == self.0 => Some(its),
+                _ => None,
+            })
+            .next()
+            .ok_or_else(|| TestError::RsCodeExaminationFail("Couldn't find item".into()))?;
+        // Ensure doc attribute
+        error_item
+            .attrs
+            .into_iter()
+            .find(|a| a.path.get_ident().filter(|p| *p == "doc").is_some())
+            .ok_or_else(|| TestError::RsCodeExaminationFail("Item had no docs".into()))?;
+        Ok(())
+    }
+}
+
+fn find_ffi_items(f: syn::File) -> Result<Vec<Item>, TestError> {
+    let md = f
+        .items
+        .into_iter()
+        .filter_map(|i| match i {
+            Item::Mod(itm) => Some(itm),
+            _ => None,
+        })
+        .next()
+        .ok_or_else(|| TestError::RsCodeExaminationFail("No mods in file".into()))?;
+    let mut items = Vec::new();
+    find_all_non_mod_items(md, &mut items);
+    Ok(items)
+}
+
+fn find_all_non_mod_items(md: syn::ItemMod, items: &mut Vec<Item>) {
+    let (more_mods, mut these_items): (Vec<_>, Vec<_>) = md
+        .content
+        .into_iter()
+        .flat_map(|(_, more_items)| more_items.into_iter())
+        .partition_map(|i| match i {
+            Item::Mod(itm) => Either::Left(itm),
+            _ => Either::Right(i),
+        });
+    items.append(&mut these_items);
+    for md in more_mods.into_iter() {
+        find_all_non_mod_items(md, items);
+    }
+}
+
+struct StringFinder(Vec<String>);
+
+impl CodeCheckerFns for StringFinder {
+    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
+        let toks = rs.to_token_stream().to_string();
+        for msg in &self.0 {
+            if !toks.contains(msg) {
+                return Err(TestError::RsCodeExaminationFail(format!(
+                    "Couldn't find string '{}'",
+                    msg
+                )));
+            };
+        }
+        Ok(())
+    }
+}
+
+/// Returns a code checker which simply hunts for a given string in the results
+pub(crate) fn make_string_finder(error_texts: Vec<String>) -> CodeChecker {
+    Box::new(StringFinder(error_texts))
+}
+
+struct RustCodeFinder(Vec<TokenStream>);
+
+impl CodeCheckerFns for RustCodeFinder {
+    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
+        let haystack = rs.to_token_stream().to_string();
+        for msg in &self.0 {
+            let needle = msg.to_string();
+            if !haystack.contains(&needle) {
+                return Err(TestError::RsCodeExaminationFail(format!(
+                    "Couldn't find tokens '{}'",
+                    needle
+                )));
+            };
+        }
+        Ok(())
+    }
+}
+
+/// Returns a code checker which hunts for the given Rust tokens in the output
+pub(crate) fn make_rust_code_finder(code: Vec<TokenStream>) -> CodeChecker {
+    Box::new(RustCodeFinder(code))
+}
+
+/// Searches generated C++ for strings we want to find, or want _not_ to find,
+/// or both.
+pub(crate) struct CppMatcher<'a> {
+    positive_matches: &'a [&'a str],
+    negative_matches: &'a [&'a str],
+}
+
+impl<'a> CppMatcher<'a> {
+    pub(crate) fn new(positive_matches: &'a [&'a str], negative_matches: &'a [&'a str]) -> Self {
+        Self {
+            positive_matches,
+            negative_matches,
+        }
+    }
+}
+
+impl<'a> CodeCheckerFns for CppMatcher<'a> {
+    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
+        let mut positives_needed = self.positive_matches.to_vec();
+        for filename in cpp {
+            let file = File::open(filename).unwrap();
+            let lines = BufReader::new(file).lines();
+            for l in lines.filter_map(|l| l.ok()) {
+                if self.negative_matches.iter().any(|neg| l.contains(neg)) {
+                    return Err(TestError::CppCodeExaminationFail);
+                }
+                positives_needed.retain(|pos| !l.contains(pos));
+            }
+        }
+        if positives_needed.is_empty() {
+            Ok(())
+        } else {
+            Err(TestError::CppCodeExaminationFail)
+        }
+    }
+}
+
+pub(crate) struct NoSystemHeadersChecker;
+
+impl CodeCheckerFns for NoSystemHeadersChecker {
+    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
+        for filename in cpp {
+            let file = File::open(filename).unwrap();
+            if BufReader::new(file)
+                .lines()
+                .any(|l| l.as_ref().unwrap().starts_with("#include <"))
+            {
+                return Err(TestError::CppCodeExaminationFail);
+            }
+        }
+        Ok(())
+    }
+    fn skip_build(&self) -> bool {
+        true
+    }
+}
diff --git a/integration-tests/tests/integration_test.rs b/integration-tests/tests/integration_test.rs
new file mode 100644
index 0000000..2a3340a
--- /dev/null
+++ b/integration-tests/tests/integration_test.rs
@@ -0,0 +1,11195 @@
+// Copyright 2021 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.
+
+use crate::{
+    builder_modifiers::{
+        make_clang_arg_adder, make_cpp17_adder, EnableAutodiscover, SetSuppressSystemHeaders,
+    },
+    code_checkers::{
+        make_error_finder, make_rust_code_finder, make_string_finder, CppMatcher,
+        NoSystemHeadersChecker,
+    },
+};
+use autocxx_integration_tests::{
+    directives_from_lists, do_run_test, do_run_test_manual, run_test, run_test_ex,
+    run_test_expect_fail, run_test_expect_fail_ex, TestError,
+};
+use indoc::indoc;
+use itertools::Itertools;
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{parse_quote, Token};
+use test_log::test;
+
+#[test]
+fn test_return_void() {
+    let cxx = indoc! {"
+        void do_nothing() {
+        }
+    "};
+    let hdr = indoc! {"
+        void do_nothing();
+    "};
+    let rs = quote! {
+        ffi::do_nothing();
+    };
+    run_test(cxx, hdr, rs, &["do_nothing"], &[]);
+}
+
+#[test]
+fn test_two_funcs() {
+    let cxx = indoc! {"
+        void do_nothing1() {
+        }
+        void do_nothing2() {
+        }
+    "};
+    let hdr = indoc! {"
+        void do_nothing1();
+        void do_nothing2();
+    "};
+    let rs = quote! {
+        ffi::do_nothing1();
+        ffi::do_nothing2();
+    };
+    run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
+}
+
+#[test]
+fn test_two_funcs_with_definition() {
+    // Test to ensure C++ header isn't included twice
+    let cxx = indoc! {"
+        void do_nothing1() {
+        }
+        void do_nothing2() {
+        }
+    "};
+    let hdr = indoc! {"
+        struct Bob {
+            int a;
+        };
+        void do_nothing1();
+        void do_nothing2();
+    "};
+    let rs = quote! {
+        ffi::do_nothing1();
+        ffi::do_nothing2();
+    };
+    run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
+}
+
+#[test]
+fn test_return_i32() {
+    let cxx = indoc! {"
+        uint32_t give_int() {
+            return 5;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        uint32_t give_int();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_int(), 5);
+    };
+    run_test(cxx, hdr, rs, &["give_int"], &[]);
+}
+
+#[test]
+fn test_take_i32() {
+    let cxx = indoc! {"
+        uint32_t take_int(uint32_t a) {
+            return a + 3;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        uint32_t take_int(uint32_t a);
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::take_int(3), 6);
+    };
+    run_test(cxx, hdr, rs, &["take_int"], &[]);
+}
+
+#[test]
+fn test_nested_module() {
+    let cxx = indoc! {"
+        void do_nothing() {
+        }
+    "};
+    let hdr = indoc! {"
+        void do_nothing();
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let unexpanded_rust = quote! {
+        mod a {
+            use autocxx::prelude::*;
+
+            include_cpp!(
+                #hexathorpe include "input.h"
+                generate!("do_nothing")
+                safety!(unsafe)
+            );
+
+            pub use ffi::*;
+        }
+
+        fn main() {
+            a::do_nothing();
+        }
+    };
+
+    do_run_test_manual(cxx, hdr, unexpanded_rust, None, None).unwrap();
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/681
+#[cfg(target_pointer_width = "64")]
+fn test_return_big_ints() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t give_u32() {
+            return 5;
+        }
+        inline uint64_t give_u64() {
+            return 5;
+        }
+        inline int32_t give_i32() {
+            return 5;
+        }
+        inline int64_t give_i64() {
+            return 5;
+        }
+        inline __int128 give_i128() {
+            return 5;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_u32(), 5);
+        assert_eq!(ffi::give_u64(), 5);
+        assert_eq!(ffi::give_i32(), 5);
+        assert_eq!(ffi::give_i64(), 5);
+        assert_eq!(ffi::give_i128(), 5);
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &["give_u32", "give_u64", "give_i32", "give_i64", "give_i128"],
+        &[],
+    );
+}
+
+#[test]
+#[ignore] // because cxx doesn't support unique_ptrs to primitives.
+fn test_give_up_int() {
+    let cxx = indoc! {"
+        std::unique_ptr<uint32_t> give_up() {
+            return std::make_unique<uint32_t>(12);
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        std::unique_ptr<uint32_t> give_up();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_up().as_ref().unwrap(), 12);
+    };
+    run_test(cxx, hdr, rs, &["give_up"], &[]);
+}
+
+#[test]
+#[ignore] // because we don't yet implement UniquePtr etc. for autocxx::c_int and friends
+fn test_give_up_ctype() {
+    let cxx = indoc! {"
+        std::unique_ptr<int> give_up() {
+            return std::make_unique<int>(12);
+        }
+    "};
+    let hdr = indoc! {"
+        #include <memory>
+        std::unique_ptr<int> give_up();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_up().as_ref().unwrap(), autocxx::c_int(12));
+    };
+    run_test(cxx, hdr, rs, &["give_up"], &[]);
+}
+
+#[test]
+fn test_give_string_up() {
+    let cxx = indoc! {"
+        std::unique_ptr<std::string> give_str_up() {
+            return std::make_unique<std::string>(\"Bob\");
+        }
+    "};
+    let hdr = indoc! {"
+        #include <memory>
+        #include <string>
+        std::unique_ptr<std::string> give_str_up();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_str_up().as_ref().unwrap().to_str().unwrap(), "Bob");
+    };
+    run_test(cxx, hdr, rs, &["give_str_up"], &[]);
+}
+
+#[test]
+fn test_give_string_plain() {
+    let cxx = indoc! {"
+        std::string give_str() {
+            return std::string(\"Bob\");
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        std::string give_str();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_str().as_ref().unwrap(), "Bob");
+    };
+    run_test(cxx, hdr, rs, &["give_str"], &[]);
+}
+
+#[test]
+fn test_cycle_string_up() {
+    let cxx = indoc! {"
+        std::unique_ptr<std::string> give_str_up() {
+            return std::make_unique<std::string>(\"Bob\");
+        }
+        uint32_t take_str_up(std::unique_ptr<std::string> a) {
+            return a->length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <memory>
+        #include <string>
+        #include <cstdint>
+        std::unique_ptr<std::string> give_str_up();
+        uint32_t take_str_up(std::unique_ptr<std::string> a);
+    "};
+    let rs = quote! {
+        let s = ffi::give_str_up();
+        assert_eq!(ffi::take_str_up(s), 3);
+    };
+    run_test(cxx, hdr, rs, &["give_str_up", "take_str_up"], &[]);
+}
+
+#[test]
+fn test_cycle_string() {
+    let cxx = indoc! {"
+        std::string give_str() {
+            return std::string(\"Bob\");
+        }
+        uint32_t take_str(std::string a) {
+            return a.length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+        std::string give_str();
+        uint32_t take_str(std::string a);
+    "};
+    let rs = quote! {
+        let s = ffi::give_str();
+        assert_eq!(ffi::take_str(s), 3);
+    };
+    let generate = &["give_str", "take_str"];
+    run_test(cxx, hdr, rs, generate, &[]);
+}
+
+#[test]
+fn test_cycle_string_by_ref() {
+    let cxx = indoc! {"
+        std::unique_ptr<std::string> give_str() {
+            return std::make_unique<std::string>(\"Bob\");
+        }
+        uint32_t take_str(const std::string& a) {
+            return a.length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        #include <cstdint>
+        std::unique_ptr<std::string> give_str();
+        uint32_t take_str(const std::string& a);
+    "};
+    let rs = quote! {
+        let s = ffi::give_str();
+        assert_eq!(ffi::take_str(s.as_ref().unwrap()), 3);
+    };
+    let generate = &["give_str", "take_str"];
+    run_test(cxx, hdr, rs, generate, &[]);
+}
+
+#[test]
+fn test_cycle_string_by_mut_ref() {
+    let cxx = indoc! {"
+        std::unique_ptr<std::string> give_str() {
+            return std::make_unique<std::string>(\"Bob\");
+        }
+        uint32_t take_str(std::string& a) {
+            return a.length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        #include <cstdint>
+        std::unique_ptr<std::string> give_str();
+        uint32_t take_str(std::string& a);
+    "};
+    let rs = quote! {
+        let mut s = ffi::give_str();
+        assert_eq!(ffi::take_str(s.as_mut().unwrap()), 3);
+    };
+    let generate = &["give_str", "take_str"];
+    run_test(cxx, hdr, rs, generate, &[]);
+}
+
+#[test]
+fn test_give_pod_by_value() {
+    let cxx = indoc! {"
+        Bob give_bob() {
+            Bob a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        Bob give_bob();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_give_pod_class_by_value() {
+    let cxx = indoc! {"
+        Bob give_bob() {
+            Bob a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        class Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+        };
+        Bob give_bob();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_give_pod_by_up() {
+    let cxx = indoc! {"
+        std::unique_ptr<Bob> give_bob() {
+            auto a = std::make_unique<Bob>();
+            a->a = 3;
+            a->b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        std::unique_ptr<Bob> give_bob();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob().as_ref().unwrap().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_pod_by_value() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_negative_take_as_pod_with_destructor() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+            inline ~Bob() {}
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_negative_take_as_pod_with_move_constructor() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <type_traits>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+            inline Bob(Bob&& other_bob) {}
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_as_pod_with_is_relocatable() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <type_traits>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+            inline Bob() {}
+            inline ~Bob() {}
+            inline Bob(Bob&& other_bob) { a = other_bob.a; b = other_bob.b; }
+            using IsRelocatable = std::true_type;
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_pod_by_ref() {
+    let cxx = indoc! {"
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob(const Bob& a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(&a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_pod_by_ref_and_ptr() {
+    let cxx = indoc! {"
+        uint32_t take_bob_ref(const Bob& a) {
+            return a.a;
+        }
+        uint32_t take_bob_ptr(const Bob* a) {
+            return a->a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob_ref(const Bob& a);
+        uint32_t take_bob_ptr(const Bob* a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob_ref(&a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob_ref", "take_bob_ptr"], &["Bob"]);
+}
+
+#[test]
+fn test_return_pod_by_ref_and_ptr() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct B {
+            uint32_t a;
+        };
+        struct A {
+            B b;
+        };
+        inline const B& return_b_ref(const A& a) {
+            return a.b;
+        }
+        inline const B* return_b_ptr(const A& a) {
+            return &a.b;
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A { b: ffi::B { a: 3 } };
+        assert_eq!(ffi::return_b_ref(&a).a, 3);
+        let b_ptr = ffi::return_b_ptr(&a);
+        assert_eq!(unsafe { b_ptr.as_ref() }.unwrap().a, 3);
+    };
+    run_test("", hdr, rs, &["return_b_ref", "return_b_ptr"], &["A", "B"]);
+}
+
+#[test]
+fn test_take_pod_by_mut_ref() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob& a) {
+            a.b = 14;
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob(Bob& a);
+    "};
+    let rs = quote! {
+        let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
+        assert_eq!(ffi::take_bob(a.as_mut()), 12);
+        assert_eq!(a.b, 14);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_nested_pod_by_value() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Phil {
+            uint32_t d;
+        };
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+            Phil c;
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13, c: ffi::Phil { d: 4 } };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    // Should be no need to allowlist Phil below
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_take_nonpod_by_value() {
+    let cxx = indoc! {"
+        Bob::Bob(uint32_t a0, uint32_t b0)
+           : a(a0), b(b0) {}
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Bob {
+            Bob(uint32_t a, uint32_t b);
+            uint32_t a;
+            uint32_t b;
+            std::string reason_why_this_is_nonpod;
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(12, 13).within_unique_ptr();
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_ref() {
+    let cxx = indoc! {"
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+        std::unique_ptr<Bob> make_bob(uint32_t a) {
+            auto b = std::make_unique<Bob>();
+            b->a = a;
+            return b;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        std::unique_ptr<Bob> make_bob(uint32_t a);
+        uint32_t take_bob(const Bob& a);
+    "};
+    let rs = quote! {
+        let a = ffi::make_bob(12);
+        assert_eq!(ffi::take_bob(&a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_up() {
+    let cxx = indoc! {"
+        uint32_t take_bob(std::unique_ptr<Bob> a) {
+            return a->a;
+        }
+        std::unique_ptr<Bob> make_bob(uint32_t a) {
+            auto b = std::make_unique<Bob>();
+            b->a = a;
+            return b;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+
+        struct NOP { inline void take_bob(); };
+        std::unique_ptr<Bob> make_bob(uint32_t a);
+        uint32_t take_bob(std::unique_ptr<Bob> a);
+    "};
+    let rs = quote! {
+        let a = ffi::make_bob(12);
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob", "NOP"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_ptr_simple() {
+    let cxx = indoc! {"
+        uint32_t take_bob(const Bob* a) {
+            return a->a;
+        }
+        std::unique_ptr<Bob> make_bob(uint32_t a) {
+            auto b = std::make_unique<Bob>();
+            b->a = a;
+            return b;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        std::unique_ptr<Bob> make_bob(uint32_t a);
+        uint32_t take_bob(const Bob* a);
+    "};
+    let rs = quote! {
+        let a = ffi::make_bob(12);
+        let a_ptr = a.into_raw();
+        assert_eq!(unsafe { ffi::take_bob(a_ptr) }, 12);
+        unsafe { cxx::UniquePtr::from_raw(a_ptr) }; // so we drop
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_ptr_in_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        #include <cstdint>
+        class A {
+        public:
+            A() {};
+            uint32_t take_bob(const Bob* a) const {
+                return a->a;
+            }
+            std::unique_ptr<Bob> make_bob(uint32_t a) const {
+                auto b = std::make_unique<Bob>();
+                b->a = a;
+                return b;
+            }
+            uint16_t a;
+        };
+
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        let b = a.as_ref().unwrap().make_bob(12);
+        let b_ptr = b.into_raw();
+        assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr) }, 12);
+        unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop
+    };
+    run_test("", hdr, rs, &["A", "Bob"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_ptr_in_wrapped_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct C {
+            C() {}
+            uint32_t a;
+        };
+        struct Bob {
+            uint32_t a;
+        };
+        class A {
+        public:
+            A() {};
+            uint32_t take_bob(const Bob* a, C) const {
+                return a->a;
+            }
+            std::unique_ptr<Bob> make_bob(uint32_t a) const {
+                auto b = std::make_unique<Bob>();
+                b->a = a;
+                return b;
+            }
+            uint16_t a;
+        };
+
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        let c = ffi::C::new().within_unique_ptr();
+        let b = a.as_ref().unwrap().make_bob(12);
+        let b_ptr = b.into_raw();
+        assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr, c) }, 12);
+        unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop
+    };
+    run_test("", hdr, rs, &["A", "Bob", "C"], &[]);
+}
+
+#[test]
+fn test_take_char_by_ptr_in_wrapped_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct C {
+            C() { test = \"hi\"; }
+            uint32_t a;
+            const char* test;
+        };
+        class A {
+        public:
+            A() {};
+            uint32_t take_char(const char* a, C) const {
+                return a[0];
+            }
+            const char* make_char(C extra) const {
+                return extra.test;
+            }
+            uint16_t a;
+        };
+
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        let c1 = ffi::C::new().within_unique_ptr();
+        let c2 = ffi::C::new().within_unique_ptr();
+        let ch = a.as_ref().unwrap().make_char(c1);
+        assert_eq!(unsafe { ch.as_ref()}.unwrap(), &104i8);
+        assert_eq!(unsafe { a.as_ref().unwrap().take_char(ch, c2) }, 104);
+    };
+    run_test("", hdr, rs, &["A", "C"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_by_mut_ref() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob& a) {
+            return a.a;
+        }
+        std::unique_ptr<Bob> make_bob(uint32_t a) {
+            auto b = std::make_unique<Bob>();
+            b->a = a;
+            return b;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        std::unique_ptr<Bob> make_bob(uint32_t a);
+        uint32_t take_bob(Bob& a);
+    "};
+    let rs = quote! {
+        let mut a = ffi::make_bob(12);
+        assert_eq!(ffi::take_bob(a.pin_mut()), 12);
+    };
+    // TODO confirm that the object really was mutated by C++ in this
+    // and similar tests.
+    run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
+}
+
+#[test]
+fn test_return_nonpod_by_value() {
+    let cxx = indoc! {"
+        Bob::Bob(uint32_t a0, uint32_t b0)
+           : a(a0), b(b0) {}
+        Bob give_bob(uint32_t a) {
+            Bob c(a, 44);
+            return c;
+        }
+        uint32_t take_bob(std::unique_ptr<Bob> a) {
+            return a->a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            Bob(uint32_t a, uint32_t b);
+            uint32_t a;
+            uint32_t b;
+        };
+        Bob give_bob(uint32_t a);
+        uint32_t take_bob(std::unique_ptr<Bob> a);
+    "};
+    let rs = quote! {
+        let a = ffi::give_bob(13).within_unique_ptr();
+        assert_eq!(ffi::take_bob(a), 13);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "give_bob", "Bob"], &[]);
+}
+
+#[test]
+fn test_get_str_by_up() {
+    let cxx = indoc! {"
+    std::unique_ptr<std::string> get_str() {
+            return std::make_unique<std::string>(\"hello\");
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        std::unique_ptr<std::string> get_str();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
+    };
+    run_test(cxx, hdr, rs, &["get_str"], &[]);
+}
+
+#[test]
+fn test_get_str_by_value() {
+    let cxx = indoc! {"
+        std::string get_str() {
+            return \"hello\";
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        std::string get_str();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
+    };
+    run_test(cxx, hdr, rs, &["get_str"], &[]);
+}
+
+#[test]
+fn test_cycle_nonpod_with_str_by_ref() {
+    let cxx = indoc! {"
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+        std::unique_ptr<Bob> make_bob() {
+            auto a = std::make_unique<Bob>();
+            a->a = 32;
+            a->b = \"hello\";
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+            std::string b;
+        };
+        uint32_t take_bob(const Bob& a);
+        std::unique_ptr<Bob> make_bob();
+    "};
+    let rs = quote! {
+        let a = ffi::make_bob();
+        assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 32);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
+}
+
+#[test]
+fn test_make_up() {
+    let cxx = indoc! {"
+        Bob::Bob() : a(3) {
+        }
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        class Bob {
+        public:
+            Bob();
+            uint32_t a;
+        };
+        uint32_t take_bob(const Bob& a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new().within_unique_ptr(); // TODO test with all sorts of arguments.
+        assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 3);
+    };
+    run_test(cxx, hdr, rs, &["Bob", "take_bob"], &[]);
+}
+
+#[test]
+fn test_make_up_with_args() {
+    let cxx = indoc! {"
+        Bob::Bob(uint32_t a0, uint32_t b0)
+           : a(a0), b(b0) {}
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            Bob(uint32_t a, uint32_t b);
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob(const Bob& a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(12, 13).within_unique_ptr();
+        assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
+}
+
+#[test]
+#[ignore] // because we don't support unique_ptrs to primitives
+fn test_make_up_int() {
+    let cxx = indoc! {"
+        Bob::Bob(uint32_t a) : b(a) {
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        class Bob {
+        public:
+            Bob(uint32_t a);
+            uint32_t b;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(3).within_unique_ptr();
+        assert_eq!(a.as_ref().unwrap().b, 3);
+    };
+    run_test(cxx, hdr, rs, &["Bob"], &[]);
+}
+
+#[test]
+fn test_enum_with_funcs() {
+    let cxx = indoc! {"
+        Bob give_bob() {
+            return Bob::BOB_VALUE_2;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        enum Bob {
+            BOB_VALUE_1,
+            BOB_VALUE_2,
+        };
+        Bob give_bob();
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::BOB_VALUE_2;
+        let b = ffi::give_bob();
+        assert!(a == b);
+    };
+    run_test(cxx, hdr, rs, &["Bob", "give_bob"], &[]);
+}
+
+#[test]
+fn test_re_export() {
+    let cxx = indoc! {"
+        Bob give_bob() {
+            return Bob::BOB_VALUE_2;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        enum Bob {
+            BOB_VALUE_1,
+            BOB_VALUE_2,
+        };
+        Bob give_bob();
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::BOB_VALUE_2;
+        let b = ffi::give_bob();
+        assert!(a == b);
+    };
+    run_test_ex(
+        cxx,
+        hdr,
+        rs,
+        directives_from_lists(&["Bob", "give_bob"], &[], None),
+        None,
+        None,
+        Some(quote! { pub use ffi::Bob; }),
+    );
+}
+
+#[test]
+fn test_enum_no_funcs() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        enum Bob {
+            BOB_VALUE_1,
+            BOB_VALUE_2,
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::BOB_VALUE_1;
+        let b = ffi::Bob::BOB_VALUE_2;
+        assert!(a != b);
+    };
+    run_test(cxx, hdr, rs, &["Bob"], &[]);
+}
+
+#[test]
+fn test_enum_with_funcs_as_pod() {
+    let cxx = indoc! {"
+        Bob give_bob() {
+            return Bob::BOB_VALUE_2;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        enum Bob {
+            BOB_VALUE_1,
+            BOB_VALUE_2,
+        };
+        Bob give_bob();
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::BOB_VALUE_2;
+        let b = ffi::give_bob();
+        assert!(a == b);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[test] // works, but causes compile warnings
+fn test_take_pod_class_by_value() {
+    let cxx = indoc! {"
+        uint32_t take_bob(Bob a) {
+            return a.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        class Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+        };
+        uint32_t take_bob(Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_pod_method() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob() const {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob() const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(a.get_bob(), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob"]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/723
+fn test_constructors_for_specialized_types() {
+    // bindgen sometimes makes such opaque types as type Bob = u32[2];
+    let hdr = indoc! {"
+        #include <cstdint>
+        template<typename T>
+        class A {
+            uint32_t foo() { return 12; };
+        private:
+            T a[2];
+        };
+
+        typedef A<uint32_t> B;
+        typedef B C;
+    "};
+    let rs = quote! {
+        let a = ffi::C::new().within_unique_ptr();
+        assert_eq!(a.foo(), 12);
+    };
+    run_test("", hdr, rs, &["C"], &[]);
+}
+
+#[test]
+fn test_pod_mut_method() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob() {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob();
+        };
+    "};
+    let rs = quote! {
+        let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
+        assert_eq!(a.as_mut().get_bob(), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob"]);
+}
+
+#[test]
+fn test_define_int() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #define BOB 3
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::BOB, 3);
+    };
+    run_test(cxx, hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_define_str() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #define BOB \"foo\"
+    "};
+    let rs = quote! {
+        assert_eq!(std::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
+    };
+    run_test(cxx, hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_i32_const() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        const uint32_t BOB = 3;
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::BOB, 3);
+    };
+    run_test(cxx, hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_negative_rs_nonsense() {
+    // Really just testing the test infrastructure.
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        const uint32_t BOB = 3;
+    "};
+    let rs = quote! {
+        foo bar
+    };
+    run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_negative_cpp_nonsense() {
+    // Really just testing the test infrastructure.
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        const uint32_t BOB = CAT;
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::BOB, 3);
+    };
+    run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_negative_make_nonpod() {
+    let cxx = indoc! {"
+        uint32_t take_bob(const Bob& a) {
+            return a.a;
+        }
+        std::unique_ptr<Bob> make_bob(uint32_t a) {
+            auto b = std::make_unique<Bob>();
+            b->a = a;
+            return b;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        std::unique_ptr<Bob> make_bob(uint32_t a);
+        uint32_t take_bob(const Bob& a);
+    "};
+    let rs = quote! {
+        ffi::Bob {};
+    };
+    let rs2 = quote! {
+        ffi::Bob { a: 12 };
+    };
+    let rs3 = quote! {
+        ffi::Bob { do_not_attempt_to_allocate_nonpod_types: [] };
+    };
+    run_test_expect_fail(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
+    run_test_expect_fail(cxx, hdr, rs2, &["take_bob", "Bob", "make_bob"], &[]);
+    run_test_expect_fail(cxx, hdr, rs3, &["take_bob", "Bob", "make_bob"], &[]);
+}
+
+#[test]
+fn test_method_pass_pod_by_value() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(Anna) const {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Anna {
+            uint32_t a;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna a) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Anna { a: 14 };
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
+}
+
+fn perform_asan_doom_test(into_raw: TokenStream, box_type: TokenStream) {
+    if std::env::var_os("AUTOCXX_ASAN").is_none() {
+        return;
+    }
+    // Testing that we get an asan fail when it's enabled.
+    // Really just testing our CI is working to spot ASAN mistakes.
+    let hdr = indoc! {"
+        #include <cstddef>
+        struct A {
+            int a;
+        };
+        inline size_t how_big_is_a() {
+            return sizeof(A);
+        }
+    "};
+    let rs = quote! {
+        let a = #box_type::emplace(ffi::A::new());
+        unsafe {
+            let a_raw = #into_raw;
+            // Intentional memory unsafety. Don't @ me.
+            let a_offset_into_doom = a_raw.offset(ffi::how_big_is_a().try_into().unwrap());
+            a_offset_into_doom.write_bytes(0x69, 1);
+            #box_type::from_raw(a_raw); // to delete. If we haven't yet crashed.
+        }
+    };
+    run_test_expect_fail("", hdr, rs, &["A", "how_big_is_a"], &[]);
+}
+
+#[test]
+fn test_asan_working_as_expected_for_cpp_allocations() {
+    perform_asan_doom_test(quote! { a.into_raw() }, quote! { UniquePtr })
+}
+
+#[test]
+fn test_asan_working_as_expected_for_rust_allocations() {
+    perform_asan_doom_test(
+        quote! { Box::into_raw(std::pin::Pin::into_inner_unchecked(a)) },
+        quote! { Box },
+    )
+}
+
+#[test]
+fn test_inline_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Anna {
+            uint32_t a;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna) const {
+                return a;
+            }
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Anna { a: 14 };
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a), 12);
+    };
+    run_test("", hdr, rs, &[], &["Bob", "Anna"]);
+}
+
+#[test]
+fn test_method_pass_pod_by_reference() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(const Anna&) const {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Anna {
+            uint32_t a;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(const Anna& a) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Anna { a: 14 };
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(&a), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
+}
+
+#[test]
+fn test_method_pass_pod_by_mut_reference() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(Anna&) const {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Anna {
+            uint32_t a;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna& a) const;
+        };
+    "};
+    let rs = quote! {
+        let mut a = Box::pin(ffi::Anna { a: 14 });
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a.as_mut()), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
+}
+
+#[test]
+fn test_method_pass_pod_by_up() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Anna {
+            uint32_t a;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(std::unique_ptr<Anna> z) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Anna { a: 14 };
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(cxx::UniquePtr::new(a)), 12);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
+}
+
+#[test]
+fn test_method_pass_nonpod_by_value() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(Anna) const {
+            return a;
+        }
+        Anna give_anna() {
+            Anna a;
+            a.a = 10;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        Anna give_anna();
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna a) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::give_anna().within_box();
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
+}
+
+#[test]
+fn test_pass_two_nonpod_by_value() {
+    let cxx = indoc! {"
+        void take_a(A, A) {
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        struct A {
+            std::string b;
+        };
+        void take_a(A, A);
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        let a2 = ffi::A::new().within_unique_ptr();
+        ffi::take_a(a, a2);
+    };
+    run_test(cxx, hdr, rs, &["A", "take_a"], &[]);
+}
+
+#[test]
+fn test_issue_931() {
+    let cxx = "";
+    let hdr = indoc! {"
+    namespace a {
+        struct __cow_string {
+          __cow_string();
+        };
+        class b {
+        public:
+          __cow_string c;
+        };
+        class j {
+        public:
+          b d;
+        };
+        template <typename> class e;
+        } // namespace a
+        template <typename> struct f {};
+        namespace llvm {
+        template <class> class g {
+          union {
+            f<a::j> h;
+          };
+        };
+        class MemoryBuffer {
+        public:
+          g<a::e<MemoryBuffer>> i;
+        };
+        } // namespace llvm
+    "};
+    let rs = quote! {};
+    run_test(cxx, hdr, rs, &["llvm::MemoryBuffer"], &[]);
+}
+
+#[test]
+fn test_issue_936() {
+    let cxx = "";
+    let hdr = indoc! {"
+    struct a;
+    class B {
+    public:
+        B(a &, bool);
+    };
+    "};
+    let rs = quote! {};
+    run_test(cxx, hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_method_pass_nonpod_by_value_with_up() {
+    // Checks that existing UniquePtr params are not wrecked
+    // by the conversion we do here.
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(Anna, std::unique_ptr<Anna>) const {
+            return a;
+        }
+        Anna give_anna() {
+            Anna a;
+            a.a = 10;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        #include <memory>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        Anna give_anna();
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna a, std::unique_ptr<Anna>) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::give_anna().within_unique_ptr();
+        let a2 = ffi::give_anna().within_unique_ptr();
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a, a2), 12);
+    };
+    run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
+}
+
+#[test]
+fn test_issue_940() {
+    let cxx = "";
+    let hdr = indoc! {"
+    template <class> class b;
+    template <class = void> struct c;
+    struct identity;
+    template <class, class, class e, class> class f {
+    using g = e;
+    g h;
+    };
+    template <class i, class k = c<>, class l = b<i>>
+    using j = f<i, identity, k, l>;
+    class n;
+    class RenderFrameHost {
+    public:
+    virtual void o(const j<n> &);
+    virtual ~RenderFrameHost() {}
+    };
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        cxx,
+        hdr,
+        rs,
+        directives_from_lists(&["RenderFrameHost"], &[], None),
+        make_cpp17_adder(),
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_method_pass_nonpod_by_reference() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(const Anna&) const {
+            return a;
+        }
+        Anna give_anna() {
+            Anna a;
+            a.a = 10;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        Anna give_anna();
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(const Anna& a) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::give_anna().within_box();
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a.as_ref().get_ref()), 12);
+    };
+    run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
+}
+
+#[test]
+fn test_method_pass_nonpod_by_mut_reference() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(Anna&) const {
+            return a;
+        }
+        Anna give_anna() {
+            Anna a;
+            a.a = 10;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        Anna give_anna();
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(Anna& a) const;
+        };
+    "};
+    let rs = quote! {
+        let mut a = ffi::give_anna().within_unique_ptr();
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a.as_mut().unwrap()), 12);
+    };
+    run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
+}
+
+#[test]
+fn test_method_pass_nonpod_by_up() {
+    let cxx = indoc! {"
+        uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
+            return a;
+        }
+        Anna give_anna() {
+            Anna a;
+            a.a = 10;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        #include <string>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        Anna give_anna();
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t get_bob(std::unique_ptr<Anna> z) const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::give_anna().within_unique_ptr();
+        let b = ffi::Bob { a: 12, b: 13 };
+        assert_eq!(b.get_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["give_anna"], &["Bob"]);
+}
+
+#[test]
+fn test_method_return_nonpod_by_value() {
+    let cxx = indoc! {"
+        Anna Bob::get_anna() const {
+            Anna a;
+            a.a = 12;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Anna {
+            uint32_t a;
+            std::string b;
+        };
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            Anna get_anna() const;
+        };
+    "};
+    let rs = quote! {
+        let b = ffi::Bob { a: 12, b: 13 };
+        let a = b.get_anna().within_unique_ptr();
+        assert!(!a.is_null());
+    };
+    run_test(cxx, hdr, rs, &["Anna"], &["Bob"]);
+}
+
+#[test]
+fn test_pass_string_by_value() {
+    let cxx = indoc! {"
+        uint32_t measure_string(std::string z) {
+            return z.length();
+        }
+        std::unique_ptr<std::string> get_msg() {
+            return std::make_unique<std::string>(\"hello\");
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        #include <memory>
+        uint32_t measure_string(std::string a);
+        std::unique_ptr<std::string> get_msg();
+    "};
+    let rs = quote! {
+        let a = ffi::get_msg();
+        let c = ffi::measure_string(a);
+        assert_eq!(c, 5);
+    };
+    run_test(cxx, hdr, rs, &["measure_string", "get_msg"], &[]);
+}
+
+#[test]
+fn test_return_string_by_value() {
+    let cxx = indoc! {"
+        std::string get_msg() {
+            return \"hello\";
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        std::string get_msg();
+    "};
+    let rs = quote! {
+        let a = ffi::get_msg();
+        assert!(a.as_ref().unwrap() == "hello");
+    };
+    run_test(cxx, hdr, rs, &["get_msg"], &[]);
+}
+
+#[test]
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+fn test_method_pass_string_by_value() {
+    let cxx = indoc! {"
+        uint32_t Bob::measure_string(std::string z) const {
+            return z.length();
+        }
+        std::unique_ptr<std::string> get_msg() {
+            return std::make_unique<std::string>(\"hello\");
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        #include <memory>
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            uint32_t measure_string(std::string a) const;
+        };
+        std::unique_ptr<std::string> get_msg();
+    "};
+    let rs = quote! {
+        let a = ffi::get_msg();
+        let b = ffi::Bob { a: 12, b: 13 };
+        let c = b.measure_string(a);
+        assert_eq!(c, 5);
+    };
+    run_test(cxx, hdr, rs, &["Bob", "get_msg"], &["Bob"]);
+}
+
+#[test]
+fn test_method_return_string_by_value() {
+    let cxx = indoc! {"
+        std::string Bob::get_msg() const {
+            return \"hello\";
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Bob {
+        public:
+            uint32_t a;
+            uint32_t b;
+            std::string get_msg() const;
+        };
+    "};
+    let rs = quote! {
+        let b = ffi::Bob { a: 12, b: 13 };
+        let a = b.get_msg();
+        assert!(a.as_ref().unwrap() == "hello");
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob"]);
+}
+
+#[test]
+fn test_pass_rust_string_by_ref() {
+    let cxx = indoc! {"
+        uint32_t measure_string(const rust::String& z) {
+            return std::string(z).length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <cxx.h>
+        uint32_t measure_string(const rust::String& z);
+    "};
+    let rs = quote! {
+        let c = ffi::measure_string(&"hello".to_string());
+        assert_eq!(c, 5);
+    };
+    run_test(cxx, hdr, rs, &["measure_string"], &[]);
+}
+
+#[test]
+fn test_pass_rust_string_by_value() {
+    let cxx = indoc! {"
+        uint32_t measure_string(rust::String z) {
+            return std::string(z).length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <cxx.h>
+        uint32_t measure_string(rust::String z);
+    "};
+    let rs = quote! {
+        let c = ffi::measure_string("hello".into());
+        assert_eq!(c, 5);
+    };
+    run_test(cxx, hdr, rs, &["measure_string"], &[]);
+}
+
+#[test]
+fn test_pass_rust_str() {
+    // passing by value is the only legal option
+    let cxx = indoc! {"
+        uint32_t measure_string(rust::Str z) {
+            return std::string(z).length();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <cxx.h>
+        uint32_t measure_string(rust::Str z);
+    "};
+    let rs = quote! {
+        let c = ffi::measure_string("hello");
+        assert_eq!(c, 5);
+    };
+    run_test(cxx, hdr, rs, &["measure_string"], &[]);
+}
+
+#[test]
+fn test_multiple_classes_with_methods() {
+    let hdr = indoc! {"
+        #include <cstdint>
+
+        struct TrivialStruct {
+            uint32_t val = 0;
+
+            uint32_t get() const;
+            uint32_t inc();
+        };
+        TrivialStruct make_trivial_struct();
+
+        class TrivialClass {
+          public:
+            uint32_t get() const;
+            uint32_t inc();
+
+          private:
+            uint32_t val_ = 1;
+        };
+        TrivialClass make_trivial_class();
+
+        struct OpaqueStruct {
+            // ~OpaqueStruct();
+            uint32_t val = 2;
+
+            uint32_t get() const;
+            uint32_t inc();
+        };
+        OpaqueStruct make_opaque_struct();
+
+        class OpaqueClass {
+          public:
+            // ~OpaqueClass();
+            uint32_t get() const;
+            uint32_t inc();
+
+          private:
+            uint32_t val_ = 3;
+        };
+        OpaqueClass make_opaque_class();
+    "};
+    let cxx = indoc! {"
+        TrivialStruct make_trivial_struct() { return {}; }
+        TrivialClass make_trivial_class() { return {}; }
+        OpaqueStruct make_opaque_struct() { return {}; }
+        OpaqueClass make_opaque_class() { return {}; }
+
+        uint32_t TrivialStruct::get() const { return val;}
+        uint32_t TrivialClass::get() const { return val_; }
+        uint32_t OpaqueStruct::get() const { return val;}
+        uint32_t OpaqueClass::get() const { return val_; }
+
+        uint32_t TrivialStruct::inc() { return ++val; }
+        uint32_t TrivialClass::inc() { return ++val_; }
+        uint32_t OpaqueStruct::inc() { return ++val; }
+        uint32_t OpaqueClass::inc() { return ++val_; }
+    "};
+    let rs = quote! {
+        use ffi::*;
+
+        let mut ts = Box::pin(make_trivial_struct());
+        assert_eq!(ts.get(), 0);
+        assert_eq!(ts.as_mut().inc(), 1);
+        assert_eq!(ts.as_mut().inc(), 2);
+
+        let mut tc = Box::pin(make_trivial_class());
+        assert_eq!(tc.get(), 1);
+        assert_eq!(tc.as_mut().inc(), 2);
+        assert_eq!(tc.as_mut().inc(), 3);
+
+        let mut os= make_opaque_struct().within_unique_ptr();
+        assert_eq!(os.get(), 2);
+        assert_eq!(os.pin_mut().inc(), 3);
+        assert_eq!(os.pin_mut().inc(), 4);
+
+        let mut oc = make_opaque_class().within_unique_ptr();
+        assert_eq!(oc.get(), 3);
+        assert_eq!(oc.pin_mut().inc(), 4);
+        assert_eq!(oc.pin_mut().inc(), 5);
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &[
+            "make_trivial_struct",
+            "make_trivial_class",
+            "make_opaque_struct",
+            "make_opaque_class",
+            "OpaqueStruct",
+            "OpaqueClass",
+        ],
+        &["TrivialStruct", "TrivialClass"],
+    );
+}
+
+#[test]
+fn test_ns_return_struct() {
+    let cxx = indoc! {"
+        A::B::Bob give_bob() {
+            A::B::Bob a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            namespace B {
+                struct Bob {
+                    uint32_t a;
+                    uint32_t b;
+                };
+            }
+        }
+        A::B::Bob give_bob();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["A::B::Bob"]);
+}
+
+#[test]
+fn test_ns_take_struct() {
+    let cxx = indoc! {"
+    uint32_t take_bob(A::B::Bob a) {
+        return a.a;
+    }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            namespace B {
+                struct Bob {
+                    uint32_t a;
+                    uint32_t b;
+                };
+            }
+        }
+        uint32_t take_bob(A::B::Bob a);
+    "};
+    let rs = quote! {
+        let a = ffi::A::B::Bob { a: 12, b: 13 };
+        assert_eq!(ffi::take_bob(a), 12);
+    };
+    run_test(cxx, hdr, rs, &["take_bob"], &["A::B::Bob"]);
+}
+
+#[test]
+fn test_ns_func() {
+    let cxx = indoc! {"
+        using namespace C;
+        A::B::Bob C::give_bob() {
+            A::B::Bob a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            namespace B {
+                struct Bob {
+                    uint32_t a;
+                    uint32_t b;
+                };
+            }
+        }
+        namespace C {
+            ::A::B::Bob give_bob();
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::C::give_bob().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["C::give_bob"], &["A::B::Bob"]);
+}
+
+#[test]
+fn test_overload_constructors() {
+    let cxx = indoc! {"
+        Bob::Bob() {}
+        Bob::Bob(uint32_t _a) :a(_a) {}
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            Bob();
+            Bob(uint32_t a);
+            uint32_t a;
+            uint32_t b;
+        };
+    "};
+    let rs = quote! {
+        ffi::Bob::new().within_unique_ptr();
+        ffi::Bob::new1(32).within_unique_ptr();
+    };
+    run_test(cxx, hdr, rs, &["Bob"], &[]);
+}
+
+#[test]
+fn test_overload_functions() {
+    let cxx = indoc! {"
+        void daft(uint32_t) {}
+        void daft(uint8_t) {}
+        void daft(std::string) {}
+        void daft(Fred) {}
+        void daft(Norma) {}
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Fred {
+            uint32_t a;
+        };
+        struct Norma {
+            Norma() {}
+            uint32_t a;
+        };
+        void daft(uint32_t);
+        void daft(uint8_t);
+        void daft(std::string);
+        void daft(Fred);
+        void daft(Norma);
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        ffi::daft(32);
+        ffi::daft1(8);
+        ffi::daft2("hello".into_cpp());
+        let b = ffi::Fred { a: 3 };
+        ffi::daft3(b);
+        let c = ffi::Norma::new().within_unique_ptr();
+        ffi::daft4(c);
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
+        &["Fred"],
+    );
+}
+
+#[test]
+#[ignore] // At present, bindgen generates two separate 'daft1'
+          // functions here, and there's not much we can do about that.
+fn test_overload_numeric_functions() {
+    // Because bindgen deals with conflicting overloaded functions by
+    // appending a numeric suffix, let's see if we can cope.
+    let cxx = indoc! {"
+        void daft1(uint32_t) {}
+        void daft2(uint8_t) {}
+        void daft(std::string) {}
+        void daft(Fred) {}
+        void daft(Norma) {}
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Fred {
+            uint32_t a;
+        };
+        struct Norma {
+            uint32_t a;
+        };
+        void daft1(uint32_t a);
+        void daft2(uint8_t a);
+        void daft(std::string a);
+        void daft(Fred a);
+        void daft(Norma a);
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        ffi::daft(32);
+        ffi::daft1(8);
+        ffi::daft2("hello".into_cpp());
+        let b = ffi::Fred { a: 3 };
+        ffi::daft3(b);
+        let c = ffi::Norma::new().within_unique_ptr();
+        ffi::daft4(c);
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
+        &["Fred"],
+    );
+}
+
+#[test]
+fn test_overload_methods() {
+    let cxx = indoc! {"
+        void Bob::daft(uint32_t) const {}
+        void Bob::daft(uint8_t) const {}
+        void Bob::daft(std::string) const {}
+        void Bob::daft(Fred) const {}
+        void Bob::daft(Norma) const {}
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Fred {
+            uint32_t a;
+        };
+        struct Norma {
+            Norma() {}
+            uint32_t a;
+        };
+        struct Bob {
+            uint32_t a;
+            void daft(uint32_t) const;
+            void daft(uint8_t) const;
+            void daft(std::string) const;
+            void daft(Fred) const;
+            void daft(Norma) const;
+        };
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        let a = ffi::Bob { a: 12 };
+        a.daft(32);
+        a.daft1(8);
+        a.daft2("hello".into_cpp());
+        let b = ffi::Fred { a: 3 };
+        a.daft3(b);
+        let c = ffi::Norma::new().within_unique_ptr();
+        a.daft4(c);
+    };
+    run_test(cxx, hdr, rs, &["Norma"], &["Fred", "Bob"]);
+}
+
+#[test]
+fn test_ns_constructor() {
+    let cxx = indoc! {"
+        A::Bob::Bob() {}
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                Bob();
+                uint32_t a;
+                uint32_t b;
+            };
+        }
+    "};
+    let rs = quote! {
+        ffi::A::Bob::new().within_unique_ptr();
+    };
+    run_test(cxx, hdr, rs, &["A::Bob"], &[]);
+}
+
+#[test]
+fn test_ns_up_direct() {
+    let cxx = indoc! {"
+        std::unique_ptr<A::Bob> A::get_bob() {
+            A::Bob b;
+            b.a = 2;
+            b.b = 3;
+            return std::make_unique<A::Bob>(b);
+        }
+        uint32_t give_bob(A::Bob bob) {
+            return bob.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                uint32_t b;
+            };
+            std::unique_ptr<Bob> get_bob();
+        }
+        uint32_t give_bob(A::Bob bob);
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob(ffi::A::get_bob()), 2);
+    };
+    run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
+}
+
+#[test]
+fn test_ns_up_wrappers() {
+    let cxx = indoc! {"
+        A::Bob get_bob() {
+            A::Bob b;
+            b.a = 2;
+            b.b = 3;
+            return b;
+        }
+        uint32_t give_bob(A::Bob bob) {
+            return bob.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                uint32_t b;
+            };
+        }
+        A::Bob get_bob();
+        uint32_t give_bob(A::Bob bob);
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob(as_new(ffi::get_bob())), 2);
+    };
+    run_test(cxx, hdr, rs, &["give_bob", "get_bob"], &[]);
+}
+
+#[test]
+fn test_ns_up_wrappers_in_up() {
+    let cxx = indoc! {"
+        A::Bob A::get_bob() {
+            A::Bob b;
+            b.a = 2;
+            b.b = 3;
+            return b;
+        }
+        uint32_t give_bob(A::Bob bob) {
+            return bob.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                uint32_t b;
+            };
+            Bob get_bob();
+        }
+        uint32_t give_bob(A::Bob bob);
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob(as_new(ffi::A::get_bob())), 2);
+    };
+    run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
+}
+
+#[test]
+fn test_return_reference() {
+    let cxx = indoc! {"
+        const Bob& give_bob(const Bob& input_bob) {
+            return input_bob;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        const Bob& give_bob(const Bob& input_bob);
+    "};
+    let rs = quote! {
+        let b = ffi::Bob { a: 3, b: 4 };
+        assert_eq!(ffi::give_bob(&b).b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[test]
+fn test_return_reference_non_pod() {
+    let cxx = indoc! {"
+        const Bob& give_bob(const Bob& input_bob) {
+            return input_bob;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        namespace A {
+            void give_bob(); // force wrapper generation
+        }
+        const Bob& give_bob(const Bob& input_bob);
+    "};
+    let rs = quote! {};
+    run_test(cxx, hdr, rs, &["give_bob", "Bob", "A::give_bob"], &[]);
+}
+
+#[test]
+fn test_return_reference_non_pod_string() {
+    let cxx = indoc! {"
+        const std::string& give_bob(const Bob& input_bob) {
+            return input_bob.a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <string>
+        struct Bob {
+            std::string a;
+        };
+       // namespace A {
+       //     void give_bob(); // force wrapper generation
+       // }
+        const std::string& give_bob(const Bob& input_bob);
+    "};
+    let rs = quote! {};
+    run_test(cxx, hdr, rs, &["give_bob", "Bob"], &[]);
+}
+
+#[test]
+fn test_member_return_reference() {
+    let hdr = indoc! {"
+        #include <string>
+        class A {
+        public:
+            virtual const std::string& get_str() { return a; }
+            virtual ~A() {}
+            std::string a;
+        };
+    "};
+    let rs = quote! {
+        let mut b = ffi::A::new().within_unique_ptr();
+        b.pin_mut().get_str();
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_destructor() {
+    let hdr = indoc! {"
+        struct WithDtor {
+            ~WithDtor();
+        };
+        WithDtor make_with_dtor();
+    "};
+    let cxx = indoc! {"
+        WithDtor::~WithDtor() {}
+        WithDtor make_with_dtor() {
+            return {};
+        }
+    "};
+    let rs = quote! {
+        use ffi::*;
+        let with_dtor: cxx::UniquePtr<WithDtor> = make_with_dtor().within_unique_ptr();
+        drop(with_dtor);
+    };
+    run_test(cxx, hdr, rs, &["WithDtor", "make_with_dtor"], &[]);
+}
+
+#[test]
+fn test_nested_with_destructor() {
+    // Regression test, naming the destructor in the generated C++ is a bit tricky.
+    let hdr = indoc! {"
+        struct A {
+            struct B {
+                B() = default;
+                ~B() = default;
+            };
+        };
+    "};
+    let rs = quote! {
+        ffi::A_B::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["A", "A_B"], &[]);
+}
+
+// Even without a `safety!`, we still need to generate a safe `fn drop`.
+#[test]
+fn test_destructor_no_safety() {
+    let hdr = indoc! {"
+        struct WithDtor {
+            ~WithDtor();
+        };
+    "};
+    let cxx = indoc! {"
+        WithDtor::~WithDtor() {}
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let unexpanded_rust = quote! {
+        use autocxx::prelude::*;
+
+        include_cpp!(
+            #hexathorpe include "input.h"
+            generate!("WithDtor")
+        );
+
+        fn main() {}
+    };
+
+    do_run_test_manual(cxx, hdr, unexpanded_rust, None, None).unwrap();
+}
+
+#[test]
+fn test_static_func() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct WithStaticMethod {
+            static uint32_t call();
+        };
+    "};
+    let cxx = indoc! {"
+        uint32_t WithStaticMethod::call() {
+            return 42;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::WithStaticMethod::call(), 42);
+    };
+    run_test(cxx, hdr, rs, &["WithStaticMethod"], &[]);
+}
+
+#[test]
+fn test_static_func_wrapper() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct A {
+            std::string a;
+            static A CreateA(std::string a, std::string) {
+                A c;
+                c.a = a;
+                return c;
+            }
+        };
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        ffi::A::CreateA("a".into_cpp(), "b".into_cpp());
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_give_pod_typedef_by_value() {
+    let cxx = indoc! {"
+        Horace give_bob() {
+            Horace a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        using Horace = Bob;
+        Horace give_bob();
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_bob().b, 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
+}
+
+#[ignore] // because we need to put some aliases in the output ffi mod.
+#[test]
+fn test_use_pod_typedef() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        using Horace = Bob;
+    "};
+    let rs = quote! {
+        let h = Horace { a: 3, b: 4 };
+        assert_eq!(h.b, 4);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob"]);
+}
+
+#[test]
+fn test_typedef_to_ns() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            template<typename T>
+            struct C {
+                T* t;
+            };
+            typedef C<char> B;
+        }
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A::B"], &[]);
+}
+
+#[ignore] // we don't yet allow typedefs to be listed in allow_pod
+#[test]
+fn test_use_pod_typedef_with_allowpod() {
+    let cxx = indoc! {"
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        using Horace = Bob;
+    "};
+    let rs = quote! {
+        let h = Horace { a: 3, b: 4 };
+        assert_eq!(h.b, 4);
+    };
+    run_test(cxx, hdr, rs, &[], &["Horace"]);
+}
+
+#[test]
+fn test_give_nonpod_typedef_by_value() {
+    let cxx = indoc! {"
+        Horace give_bob() {
+            Horace a;
+            a.a = 3;
+            a.b = 4;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t b;
+        };
+        using Horace = Bob;
+        Horace give_bob();
+        inline uint32_t take_horace(const Horace& horace) { return horace.b; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::take_horace(&moveit!(ffi::give_bob())), 4);
+    };
+    run_test(cxx, hdr, rs, &["give_bob", "take_horace"], &[]);
+}
+
+#[test]
+fn test_conflicting_static_functions() {
+    let cxx = indoc! {"
+        Bob Bob::create() { Bob a; return a; }
+        Fred Fred::create() { Fred b; return b; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            Bob() : a(0) {}
+            uint32_t a;
+            static Bob create();
+        };
+        struct Fred {
+            Fred() : b(0) {}
+            uint32_t b;
+            static Fred create();
+        };
+    "};
+    let rs = quote! {
+        ffi::Bob::create();
+        ffi::Fred::create();
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
+}
+
+#[test]
+fn test_conflicting_ns_up_functions() {
+    let cxx = indoc! {"
+        uint32_t A::create(C) { return 3; }
+        uint32_t B::create(C) { return 4; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct C {
+            C() {}
+            uint32_t a;
+        };
+        namespace A {
+            uint32_t create(C c);
+        };
+        namespace B {
+            uint32_t create(C c);
+        };
+    "};
+    let rs = quote! {
+        let c = ffi::C::new().within_unique_ptr();
+        let c2 = ffi::C::new().within_unique_ptr();
+        assert_eq!(ffi::A::create(c), 3);
+        assert_eq!(ffi::B::create(c2), 4);
+    };
+    run_test(cxx, hdr, rs, &["A::create", "B::create", "C"], &[]);
+}
+
+#[test]
+fn test_conflicting_methods() {
+    let cxx = indoc! {"
+        uint32_t Bob::get() const { return a; }
+        uint32_t Fred::get() const { return b; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+            uint32_t get() const;
+        };
+        struct Fred {
+            uint32_t b;
+            uint32_t get() const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 10 };
+        let b = ffi::Fred { b: 20 };
+        assert_eq!(a.get(), 10);
+        assert_eq!(b.get(), 20);
+    };
+    run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
+}
+
+#[test]
+// There's a bindgen bug here. bindgen generates
+// functions called 'get' and 'get1' but then generates impl
+// blocks which call 'get' and 'get'. By luck, we currently
+// should not be broken by this, but at some point we should take
+// the time to create a minimal bindgen test case and submit it
+// as a bindgen bug.
+fn test_conflicting_up_wrapper_methods_not_in_ns() {
+    // Ensures the two names 'get' do not conflict in the flat
+    // cxx::bridge mod namespace.
+    let cxx = indoc! {"
+        Bob::Bob() : a(\"hello\") {}
+        Fred::Fred() : b(\"goodbye\") {}
+        std::string Bob::get() const { return a; }
+        std::string Fred::get() const { return b; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Bob {
+            Bob();
+            std::string a;
+            std::string get() const;
+        };
+        struct Fred {
+            Fred();
+            std::string b;
+            std::string get() const;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new().within_unique_ptr();
+        let b = ffi::Fred::new().within_unique_ptr();
+        assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
+        assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
+    };
+    run_test(cxx, hdr, rs, &["Bob", "Fred"], &[]);
+}
+
+#[test]
+fn test_conflicting_methods_in_ns() {
+    let cxx = indoc! {"
+        uint32_t A::Bob::get() const { return a; }
+        uint32_t B::Fred::get() const { return b; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                uint32_t get() const;
+            };
+        }
+        namespace B {
+            struct Fred {
+                uint32_t b;
+                uint32_t get() const;
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob { a: 10 };
+        let b = ffi::B::Fred { b: 20 };
+        assert_eq!(a.get(), 10);
+        assert_eq!(b.get(), 20);
+    };
+    run_test(cxx, hdr, rs, &[], &["A::Bob", "B::Fred"]);
+}
+
+#[test]
+fn test_conflicting_up_wrapper_methods_in_ns() {
+    let cxx = indoc! {"
+        A::Bob::Bob() : a(\"hello\") {}
+        B::Fred::Fred() : b(\"goodbye\") {}
+        std::string A::Bob::get() const { return a; }
+        std::string B::Fred::get() const { return b; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        namespace A {
+            struct Bob {
+                Bob();
+                std::string a;
+                std::string get() const;
+            };
+        }
+        namespace B {
+            struct Fred {
+                Fred();
+                std::string b;
+                std::string get() const;
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob::new().within_unique_ptr();
+        let b = ffi::B::Fred::new().within_unique_ptr();
+        assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
+        assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
+    };
+    run_test(cxx, hdr, rs, &["A::Bob", "B::Fred"], &[]);
+}
+
+#[test]
+fn test_ns_struct_pod_request() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+    "};
+    let rs = quote! {
+        ffi::A::Bob { a: 12 };
+    };
+    run_test("", hdr, rs, &[], &["A::Bob"]);
+}
+
+#[test]
+fn test_conflicting_ns_funcs() {
+    let cxx = indoc! {"
+        uint32_t A::get() { return 10; }
+        uint32_t B::get() { return 20; }
+    "};
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            uint32_t get();
+        }
+        namespace B {
+            uint32_t get();
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::A::get(), 10);
+        assert_eq!(ffi::B::get(), 20);
+    };
+    run_test(cxx, hdr, rs, &["A::get", "B::get"], &[]);
+}
+
+#[ignore]
+// because currently we feed a flat namespace to cxx
+// This would be relatively easy to enable now that we have the facility
+// to add aliases to the 'use' statements we generate, plus
+// bridge_name_tracker to pick a unique name. TODO.
+#[test]
+fn test_conflicting_ns_structs() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+    "};
+    let rs = quote! {
+        ffi::A::Bob { a: 12 };
+        ffi::B::Bob { b: 12 };
+    };
+    run_test("", hdr, rs, &[], &["A::Bob", "B::Bob"]);
+}
+
+#[test]
+fn test_make_string() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+        };
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        let a = "hello".into_cpp();
+        assert_eq!(a.to_str().unwrap(), "hello");
+    };
+    run_test("", hdr, rs, &["Bob"], &[]);
+}
+
+#[test]
+fn test_string_make_unique() {
+    let hdr = indoc! {"
+        #include <string>
+        inline void take_string(const std::string*) {};
+    "};
+    let rs = quote! {
+        let s = ffi::make_string("");
+        unsafe { ffi::take_string(s.as_ref().unwrap()) };
+    };
+    run_test("", hdr, rs, &["take_string"], &[]);
+}
+
+#[test]
+fn test_string_constant() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        const char* STRING = \"Foo\";
+    "};
+    let rs = quote! {
+        let a = std::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
+        assert_eq!(a, "Foo");
+    };
+    run_test("", hdr, rs, &["STRING"], &[]);
+}
+
+#[test]
+fn test_string_let_cxx_string() {
+    let hdr = indoc! {"
+        #include <string>
+        inline void take_string(const std::string&) {};
+    "};
+    let rs = quote! {
+        autocxx::cxx::let_cxx_string!(s = "hello");
+        ffi::take_string(&s);
+    };
+    run_test("", hdr, rs, &["take_string"], &[]);
+}
+
+#[test]
+fn test_pod_constant_harmless_inside_type() {
+    // Check that the presence of this constant doesn't break anything.
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+        };
+        struct Anna {
+            uint32_t a;
+            const Bob BOB = Bob { 10 };
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["Anna"]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/93
+fn test_pod_constant() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+        };
+        const Bob BOB = Bob { 10 };
+    "};
+    let rs = quote! {
+        let a = &ffi::BOB;
+        assert_eq!(a.a, 10);
+    };
+    run_test("", hdr, rs, &["BOB"], &["Bob"]);
+}
+
+#[test]
+fn test_pod_static_harmless_inside_type() {
+    // Check that the presence of this constant doesn't break anything.
+    // Remove this test when the following one is enabled.
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+        };
+        struct Anna {
+            uint32_t a;
+            static Bob BOB;
+        };
+        Bob Anna::BOB = Bob { 10 };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["Anna"]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/93
+fn test_pod_static() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct Bob {
+            uint32_t a;
+        };
+        static Bob BOB = Bob { 10 };
+    "};
+    let rs = quote! {
+        let a = &ffi::BOB;
+        assert_eq!(a.a, 10);
+    };
+    run_test("", hdr, rs, &["BOB"], &["Bob"]);
+}
+
+#[test]
+#[ignore] // this probably requires code generation on the C++
+          // side. It's not at all clear how best to handle this.
+fn test_non_pod_constant() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        struct Bob {
+            std::string a;
+            std::string get() { return a };
+        };
+        const Bob BOB = Bob { \"hello\" };
+    "};
+    let rs = quote! {
+        let a = ffi::BOB;
+        // following line assumes that 'a' is a &Bob
+        // but who knows how we'll really do this.
+        assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
+    };
+    run_test("", hdr, rs, &["BOB"], &[]);
+}
+
+#[test]
+fn test_templated_typedef() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            const STRING_TYPE* ptr_;
+            size_t length_;
+        };
+        typedef BasicStringPiece<uint8_t> StringPiece;
+
+        struct Origin {
+            Origin() {}
+            StringPiece host;
+        };
+    "};
+    let rs = quote! {
+        ffi::Origin::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["Origin"], &[]);
+}
+
+#[test]
+fn test_struct_templated_typedef() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        struct Concrete {
+            uint8_t a;
+        };
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            const STRING_TYPE* ptr_;
+            size_t length_;
+        };
+        typedef BasicStringPiece<Concrete> StringPiece;
+
+        struct Origin {
+            Origin() {}
+            StringPiece host;
+        };
+    "};
+    let rs = quote! {
+        ffi::Origin::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["Origin"], &[]);
+}
+
+#[test]
+fn test_enum_typedef() {
+    let hdr = indoc! {"
+        enum ConstraintSolverParameters_TrailCompression : int {
+            ConstraintSolverParameters_TrailCompression_NO_COMPRESSION = 0,
+            ConstraintSolverParameters_TrailCompression_COMPRESS_WITH_ZLIB = 1
+        };
+        typedef ConstraintSolverParameters_TrailCompression TrailCompression;
+    "};
+    let rs = quote! {
+        let _ = ffi::TrailCompression::ConstraintSolverParameters_TrailCompression_NO_COMPRESSION;
+    };
+    run_test("", hdr, rs, &["TrailCompression"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/264
+fn test_conflicting_usings() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <cstddef>
+        typedef size_t diff;
+        struct A {
+            using diff = diff;
+            diff a;
+        };
+        struct B {
+            using diff = diff;
+            diff a;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["A", "B"]);
+}
+
+#[test]
+fn test_conflicting_usings_with_self_declaration1() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <cstddef>
+        struct common_params {
+            using difference_type = ptrdiff_t;
+        };
+        template <typename Params>
+        class btree_node {
+            public:
+            using difference_type = typename Params::difference_type;
+            Params params;
+        };
+        template <typename Tree>
+        class btree_container {
+            public:
+            using difference_type = typename Tree::difference_type;
+            void clear() {}
+            Tree b;
+            uint32_t a;
+        };
+        typedef btree_container<btree_node<common_params>> my_tree;
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["my_tree"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/106
+fn test_string_templated_typedef() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            const STRING_TYPE* ptr_;
+            size_t length_;
+        };
+        typedef BasicStringPiece<std::string> StringPiece;
+
+        struct Origin {
+            Origin() {}
+            StringPiece host;
+        };
+    "};
+    let rs = quote! {
+        ffi::Origin::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["Origin"], &[]);
+}
+
+#[test]
+fn test_associated_type_problem() {
+    // Regression test for a potential bindgen bug
+    let hdr = indoc! {"
+        namespace a {
+        template <typename> class b {};
+        } // namespace a
+        class bl {
+        public:
+          a::b<bl> bm;
+        };
+        struct B {
+            int a;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_two_type_constructors() {
+    // https://github.com/google/autocxx/issues/877
+    let hdr = indoc! {"
+        struct A {
+            int a;
+        };
+        struct B {
+            int B;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[ignore] // https://github.com/rust-lang/rust-bindgen/issues/1924
+#[test]
+fn test_associated_type_templated_typedef_in_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            typedef size_t size_type;
+            typedef typename STRING_TYPE::value_type value_type;
+            const value_type* ptr_;
+            size_type length_;
+        };
+
+        typedef BasicStringPiece<std::string> StringPiece;
+
+        struct Origin {
+            // void SetHost(StringPiece host);
+            StringPiece host;
+        };
+    "};
+    let rs = quote! {
+        ffi::Origin::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["Origin"], &[]);
+}
+
+#[test]
+fn test_associated_type_templated_typedef() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            typedef size_t size_type;
+            typedef typename STRING_TYPE::value_type value_type;
+            const value_type* ptr_;
+            size_type length_;
+        };
+
+        typedef BasicStringPiece<std::string> StringPiece;
+
+        struct Container {
+            Container() {}
+            const StringPiece& get_string_piece() const { return sp; }
+            StringPiece sp;
+        };
+
+        inline void take_string_piece(const StringPiece&) {}
+    "};
+    let rs = quote! {
+        let sp = ffi::Container::new().within_box();
+        ffi::take_string_piece(sp.get_string_piece());
+    };
+    run_test("", hdr, rs, &["take_string_piece", "Container"], &[]);
+}
+
+#[test]
+fn test_associated_type_templated_typedef_by_value_regular() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            BasicStringPiece() : ptr_(nullptr), length_(0) {}
+            typedef size_t size_type;
+            typedef typename STRING_TYPE::value_type value_type;
+            const value_type* ptr_;
+            size_type length_;
+        };
+
+        typedef BasicStringPiece<std::string> StringPiece;
+
+        inline StringPiece give_string_piece() {
+            StringPiece s;
+            return s;
+        }
+        inline void take_string_piece(StringPiece) {}
+    "};
+    let rs = quote! {
+        let sp = ffi::give_string_piece();
+        ffi::take_string_piece(sp);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate!("take_string_piece")
+            generate!("give_string_piece")
+            instantiable!("StringPiece")
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_associated_type_templated_typedef_by_value_forward_declaration() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+
+        template <typename STRING_TYPE> class BasicStringPiece;
+
+        typedef BasicStringPiece<std::string> StringPiece;
+
+        struct Container {
+            StringPiece give_string_piece() const;
+            void take_string_piece(StringPiece string_piece) const;
+            const StringPiece& get_string_piece() const;
+            uint32_t b;
+        };
+
+        inline void take_string_piece_by_ref(const StringPiece&) {}
+    "};
+    let cpp = indoc! {"
+        template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+            BasicStringPiece() : ptr_(nullptr), length_(0) {}
+            typedef size_t size_type;
+            typedef typename STRING_TYPE::value_type value_type;
+            const value_type* ptr_;
+            size_type length_;
+        };
+
+        StringPiece Container::give_string_piece() const {
+            StringPiece s;
+            return s;
+        }
+        void Container::take_string_piece(StringPiece) const {}
+
+        StringPiece a;
+
+        const StringPiece& Container::get_string_piece() const {
+            return a;
+        }
+    "};
+    // As this template is forward declared we shouldn't be able to pass it by
+    // value, but we still want to be able to use it by reference.
+    let rs = quote! {
+        let cont = ffi::Container::new().within_box();
+        ffi::take_string_piece_by_ref(cont.as_ref().get_string_piece());
+    };
+    run_test(
+        cpp,
+        hdr,
+        rs,
+        &["take_string_piece_by_ref", "Container"],
+        &[],
+    );
+}
+
+#[test]
+fn test_remove_cv_t_pathological() {
+    let hdr = indoc! {"
+        template <class _Ty>
+        struct remove_cv {
+            using type = _Ty;
+            template <template <class> class _Fn>
+            using _Apply = _Fn<_Ty>;
+        };
+
+        template <class _Ty>
+        struct remove_cv<const _Ty> {
+            using type = _Ty;
+            template <template <class> class _Fn>
+            using _Apply = const _Fn<_Ty>;
+        };
+
+        template <class _Ty>
+        struct remove_cv<volatile _Ty> {
+            using type = _Ty;
+            template <template <class> class _Fn>
+            using _Apply = volatile _Fn<_Ty>;
+        };
+
+        template <class _Ty>
+        struct remove_cv<const volatile _Ty> {
+            using type = _Ty;
+            template <template <class> class _Fn>
+            using _Apply = const volatile _Fn<_Ty>;
+        };
+
+        template <class _Ty>
+        using remove_cv_t = typename remove_cv<_Ty>::type;
+
+        template <class _Ty>
+        struct remove_reference {
+            using type                 = _Ty;
+            using _Const_thru_ref_type = const _Ty;
+        };
+
+        template <class _Ty>
+        struct remove_reference<_Ty&> {
+            using type                 = _Ty;
+            using _Const_thru_ref_type = const _Ty&;
+        };
+
+        template <class _Ty>
+        struct remove_reference<_Ty&&> {
+            using type                 = _Ty;
+            using _Const_thru_ref_type = const _Ty&&;
+        };
+
+        template <class _Ty>
+        using remove_reference_t = typename remove_reference<_Ty>::type;
+
+        template <class _Ty>
+        using _Remove_cvref_t = remove_cv_t<remove_reference_t<_Ty>>;
+    "};
+
+    let rs = quote! {};
+
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_all!()
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_foreign_ns_func_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            inline uint32_t daft(A::Bob a) { return a.a; }
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob { a: 12 };
+        assert_eq!(ffi::B::daft(a), 12);
+    };
+    run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
+}
+
+#[test]
+fn test_foreign_ns_func_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                Bob(uint32_t _a) :a(_a) {}
+            };
+        }
+        namespace B {
+            inline uint32_t daft(A::Bob a) { return a.a; }
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob::new(12).within_unique_ptr();
+        assert_eq!(ffi::B::daft(a), 12);
+    };
+    run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
+}
+
+#[test]
+fn test_foreign_ns_meth_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                uint32_t daft(A::Bob a) const { return a.a; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob { a: 12 };
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft(a), 12);
+    };
+    run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
+}
+
+#[test]
+fn test_foreign_ns_meth_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+                Bob(uint32_t _a) :a(_a) {}
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                uint32_t daft(A::Bob a) const { return a.a; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob::new(12).within_unique_ptr();
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft(a), 12);
+    };
+    run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_foreign_ns_cons_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                C(const A::Bob& input) : a(input.a) {}
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob { a: 12 };
+        let b = ffi::B::C::new(&a).within_unique_ptr();
+        assert_eq!(b.as_ref().unwrap().a, 12);
+    };
+    run_test("", hdr, rs, &[], &["B::C", "A::Bob"]);
+}
+
+#[test]
+fn test_foreign_ns_cons_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                Bob(uint32_t _a) :a(_a) {}
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                C(const A::Bob& input) : a(input.a) {}
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A::Bob::new(12).within_unique_ptr();
+        let b = ffi::B::C::new(&a).within_unique_ptr();
+        assert_eq!(b.as_ref().unwrap().a, 12);
+    };
+    run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_foreign_ns_func_ret_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::B::daft().a, 12);
+    };
+    run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
+}
+
+#[test]
+fn test_foreign_ns_func_ret_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
+        }
+    "};
+    let rs = quote! {
+        ffi::B::daft().within_box().as_ref();
+    };
+    run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
+}
+
+#[test]
+fn test_foreign_ns_meth_ret_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft().a, 12);
+    };
+    run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
+}
+
+#[test]
+fn test_foreign_ns_meth_ret_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        namespace A {
+            struct Bob {
+                uint32_t a;
+            };
+        }
+        namespace B {
+            struct C {
+                uint32_t a;
+                A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let b = ffi::B::C { a: 14 };
+        b.daft().within_unique_ptr().as_ref().unwrap();
+    };
+    run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_root_ns_func_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            inline uint32_t daft(Bob a) { return a.a; }
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12 };
+        assert_eq!(ffi::B::daft(a), 12);
+    };
+    run_test("", hdr, rs, &["B::daft"], &["Bob"]);
+}
+
+#[test]
+fn test_root_ns_func_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+            Bob(uint32_t _a) :a(_a) {}
+        };
+        namespace B {
+            inline uint32_t daft(Bob a) { return a.a; }
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(12).within_unique_ptr();
+        assert_eq!(ffi::B::daft(a), 12);
+    };
+    run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
+}
+
+#[test]
+fn test_root_ns_meth_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                uint32_t daft(Bob a) const { return a.a; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12 };
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft(a), 12);
+    };
+    run_test("", hdr, rs, &[], &["Bob", "B::C"]);
+}
+
+#[test]
+fn test_root_ns_meth_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+            Bob(uint32_t _a) :a(_a) {}
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                uint32_t daft(Bob a) const { return a.a; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(12).within_unique_ptr();
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft(a), 12);
+    };
+    run_test("", hdr, rs, &["Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_root_ns_cons_arg_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                C(const Bob& input) : a(input.a) {}
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob { a: 12 };
+        let b = ffi::B::C::new(&a).within_unique_ptr();
+        assert_eq!(b.as_ref().unwrap().a, 12);
+    };
+    run_test("", hdr, rs, &[], &["B::C", "Bob"]);
+}
+
+#[test]
+fn test_root_ns_cons_arg_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            Bob(uint32_t _a) :a(_a) {}
+            uint32_t a;
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                C(const Bob& input) : a(input.a) {}
+            };
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::Bob::new(12).within_unique_ptr();
+        let b = ffi::B::C::new(&a).within_unique_ptr();
+        assert_eq!(b.as_ref().unwrap().a, 12);
+    };
+    run_test("", hdr, rs, &["Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_root_ns_func_ret_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            inline Bob daft() { Bob bob; bob.a = 12; return bob; }
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::B::daft().a, 12);
+    };
+    run_test("", hdr, rs, &["B::daft"], &["Bob"]);
+}
+
+#[test]
+fn test_root_ns_func_ret_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            inline Bob daft() { Bob bob; bob.a = 12; return bob; }
+        }
+    "};
+    let rs = quote! {
+        ffi::B::daft().within_unique_ptr().as_ref().unwrap();
+    };
+    run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
+}
+
+#[test]
+fn test_root_ns_meth_ret_pod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                Bob daft() const { Bob bob; bob.a = 12; return bob; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let b = ffi::B::C { a: 12 };
+        assert_eq!(b.daft().a, 12);
+    };
+    run_test("", hdr, rs, &[], &["Bob", "B::C"]);
+}
+
+#[test]
+fn test_root_ns_meth_ret_nonpod() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct Bob {
+            uint32_t a;
+        };
+        namespace B {
+            struct C {
+                uint32_t a;
+                Bob daft() const { Bob bob; bob.a = 12; return bob; }
+            };
+        }
+    "};
+    let rs = quote! {
+        let b = ffi::B::C { a: 12 };
+        b.daft().within_unique_ptr().as_ref().unwrap();
+    };
+    run_test("", hdr, rs, &["Bob"], &["B::C"]);
+}
+
+#[test]
+fn test_forward_declaration() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <memory>
+        struct A;
+        struct B {
+            B() : a(0) {}
+            uint32_t a;
+            void daft(const A&) const {}
+            static B daft3(const A&) { B b; return b; }
+            A daft4();
+            std::unique_ptr<A> daft5();
+            const std::unique_ptr<A>& daft6();
+        };
+        A* get_a();
+        void delete_a(A*);
+    "};
+    let cpp = indoc! {"
+        struct A {
+            A() : a(0) {}
+            uint32_t a;
+        };
+        A* get_a() {
+            return new A();
+        }
+        void delete_a(A* a) {
+            delete a;
+        }
+        A B::daft4() {
+            A a;
+            return a;
+        }
+        std::unique_ptr<A> B::daft5() {
+            return std::make_unique<A>();
+        }
+        std::unique_ptr<A> fixed;
+        const std::unique_ptr<A>& B::daft6() {
+            return fixed;
+        }
+    "};
+    let rs = quote! {
+        let b = ffi::B::new().within_unique_ptr();
+        let a = ffi::get_a();
+        b.daft(unsafe { a.as_ref().unwrap() });
+        unsafe { ffi::delete_a(a) };
+    };
+    run_test(cpp, hdr, rs, &["B", "get_a", "delete_a"], &[]);
+}
+
+#[test]
+fn test_ulong() {
+    let hdr = indoc! {"
+    inline unsigned long daft(unsigned long a) { return a; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
+    };
+    run_test("", hdr, rs, &["daft"], &[]);
+}
+
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
+#[test]
+fn test_typedef_to_ulong() {
+    let hdr = indoc! {"
+        typedef unsigned long fiddly;
+        inline fiddly daft(fiddly a) { return a; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
+    };
+    run_test("", hdr, rs, &["daft"], &[]);
+}
+
+#[test]
+fn test_generate_typedef_to_ulong() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        typedef uint32_t fish_t;
+    "};
+    let rs = quote! {
+        let _: ffi::fish_t;
+    };
+    run_test("", hdr, rs, &[], &["fish_t"]);
+}
+
+#[test]
+fn test_ulong_method() {
+    let hdr = indoc! {"
+    class A {
+        public:
+        A() {};
+        unsigned long daft(unsigned long a) const { return a; }
+    };
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_ulong_wrapped_method() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    struct B {
+        B() {};
+        uint32_t a;
+    };
+    class A {
+        public:
+        A() {};
+        unsigned long daft(unsigned long a, B) const { return a; }
+    };
+    "};
+    let rs = quote! {
+        let b = ffi::B::new().within_unique_ptr();
+        let a = ffi::A::new().within_unique_ptr();
+        assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34), b), autocxx::c_ulong(34));
+    };
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_reserved_name() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t async(uint32_t a) { return a; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::async_(34), 34);
+    };
+    run_test("", hdr, rs, &["async_"], &[]);
+}
+
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
+#[test]
+fn test_nested_type() {
+    // Test that we can import APIs that use nested types.
+    // As a regression test, we also test that the nested type `A::B` doesn't conflict with the
+    // top-level type `B`. This used to cause compile errors.
+    let hdr = indoc! {"
+        struct A {
+            A() {}
+            struct B {
+                B() {}
+            };
+            enum C {};
+            using D = int;
+        };
+        struct B {
+            B() {}
+            void method_on_top_level_type() const {}
+        };
+        void take_A_B(A::B);
+        void take_A_C(A::C);
+        void take_A_D(A::D);
+    "};
+    let rs = quote! {
+        let _ = ffi::A::new().within_unique_ptr();
+        let b = ffi::B::new().within_unique_ptr();
+        b.as_ref().unwrap().method_on_top_level_type();
+    };
+    run_test("", hdr, rs, &["A", "B", "take_A_B", "take_A_C"], &[]);
+}
+
+#[test]
+fn test_nested_type_in_namespace() {
+    // Test that we can import APIs that use nested types in a namespace.
+    // We can't make this part of the previous test as autocxx drops the
+    // namespace, so `A::B` and `N::A::B` would be imported as the same
+    // type.
+    let hdr = indoc! {"
+        namespace N {
+            struct A {
+                A() {}
+                struct B {
+                    B() {}
+                };
+            };
+        };
+        void take_A_B(N::A::B);
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["take_A_B"], &[]);
+}
+
+#[test]
+fn test_nested_enum_in_namespace() {
+    let hdr = indoc! {"
+        namespace N {
+            struct A {
+                A() {}
+                enum B {
+                    C,
+                    D,
+                };
+            };
+        };
+        void take_A_B(N::A::B);
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["take_A_B"], &[]);
+}
+
+#[test]
+fn test_abstract_nested_type() {
+    let hdr = indoc! {"
+        namespace N {
+            class A {
+            public:
+                A() {}
+                class B {
+                private:
+                    B() {}
+                public:
+                    virtual ~B() {}
+                    virtual void Foo() = 0;
+                };
+            };
+        };
+        void take_A_B(const N::A::B&);
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["take_A_B", "N::A_B"], &[]);
+}
+
+#[test]
+fn test_nested_type_constructor() {
+    let hdr = indoc! {"
+        #include <string>
+        class A {
+        public:
+            class B {
+            public:
+                B(const std::string&) {}
+                int b;
+            };
+            int a;
+        };
+    "};
+    let rs = quote! {
+        ffi::A_B::new(&ffi::make_string("Hello")).within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["A_B"], &[]);
+}
+
+#[test]
+fn test_generic_type() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <string>
+        template<typename TY>
+        struct Container {
+            Container(TY a_) : a(a_) {}
+            TY a;
+        };
+        struct Secondary {
+            Secondary() {}
+            void take_a(const Container<char>) const {}
+            void take_b(const Container<uint16_t>) const {}
+            uint16_t take_c(std::string a) const { return 10 + a.size(); }
+        };
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        let item = ffi::Secondary::new().within_unique_ptr();
+        assert_eq!(item.take_c("hello".into_cpp()), 15)
+    };
+    run_test("", hdr, rs, &["Secondary"], &[]);
+}
+
+#[test]
+fn test_cycle_generic_type() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        template<typename TY>
+        struct Container {
+            Container(TY a_) : a(a_) {}
+            TY a;
+        };
+        inline Container<char> make_thingy() {
+            Container<char> a('a');
+            return a;
+        }
+        typedef Container<char> Concrete;
+        inline uint32_t take_thingy(Concrete a) {
+            return a.a;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::take_thingy(ffi::make_thingy()), 'a' as u32)
+    };
+    run_test("", hdr, rs, &["take_thingy", "make_thingy"], &[]);
+}
+
+#[test]
+fn test_virtual_fns() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        class A {
+        public:
+            A(uint32_t num) : b(num) {}
+            virtual uint32_t foo(uint32_t a) { return a+1; };
+            virtual ~A() {}
+            uint32_t b;
+        };
+        class B: public A {
+        public:
+            B() : A(3), c(4) {}
+            virtual uint32_t foo(uint32_t a) { return a+2; };
+            uint32_t c;
+        };
+    "};
+    let rs = quote! {
+        let mut a = ffi::A::new(12).within_unique_ptr();
+        assert_eq!(a.pin_mut().foo(2), 3);
+        let mut b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.pin_mut().foo(2), 4);
+    };
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_const_virtual_fns() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        class A {
+        public:
+            A(uint32_t num) : b(num) {}
+            virtual uint32_t foo(uint32_t a) const { return a+1; };
+            virtual ~A() {}
+            uint32_t b;
+        };
+        class B: public A {
+        public:
+            B() : A(3), c(4) {}
+            virtual uint32_t foo(uint32_t a) const { return a+2; };
+            uint32_t c;
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::A::new(12).within_unique_ptr();
+        assert_eq!(a.foo(2), 3);
+        let b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.foo(2), 4);
+    };
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/197
+fn test_virtual_fns_inheritance() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        class A {
+        public:
+            A(uint32_t num) : b(num) {}
+            virtual uint32_t foo(uint32_t a) { return a+1; };
+            virtual ~A() {}
+            uint32_t b;
+        };
+        class B: public A {
+        public:
+            B() : A(3), c(4) {}
+            uint32_t c;
+        };
+    "};
+    let rs = quote! {
+        let mut b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.pin_mut().foo(2), 3);
+    };
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_vector_cycle_up() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <vector>
+        #include <memory>
+        struct A {
+            uint32_t a;
+        };
+        inline uint32_t take_vec(std::unique_ptr<std::vector<A>> many_as) {
+            return many_as->size();
+        }
+        inline std::unique_ptr<std::vector<A>> get_vec() {
+            auto items = std::make_unique<std::vector<A>>();
+            items->push_back(A { 3 });
+            items->push_back(A { 4 });
+            return items;
+        }
+    "};
+    let rs = quote! {
+        let v = ffi::get_vec();
+        assert_eq!(v.as_ref().unwrap().is_empty(), false);
+        assert_eq!(ffi::take_vec(v), 2);
+    };
+    run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
+}
+
+#[test]
+fn test_vector_cycle_bare() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <vector>
+        struct A {
+            uint32_t a;
+        };
+        inline uint32_t take_vec(std::vector<A> many_as) {
+            return many_as.size();
+        }
+        inline std::vector<A> get_vec() {
+            std::vector<A> items;
+            items.push_back(A { 3 });
+            items.push_back(A { 4 });
+            return items;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::take_vec(ffi::get_vec()), 2);
+    };
+    run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
+}
+
+#[test]
+fn test_typedef_to_std() {
+    let hdr = indoc! {"
+        #include <string>
+        typedef std::string my_string;
+        inline uint32_t take_str(my_string a) {
+            return a.size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_str("hello".into_cpp()), 5);
+    };
+    run_test("", hdr, rs, &["take_str"], &[]);
+}
+
+#[test]
+fn test_typedef_to_up_in_fn_call() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        typedef std::unique_ptr<std::string> my_string;
+        inline uint32_t take_str(my_string a) {
+            return a->size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_str("hello".into_cpp()), 5);
+    };
+    run_test("", hdr, rs, &["take_str"], &[]);
+}
+
+#[test]
+fn test_typedef_in_pod_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        typedef uint32_t my_int;
+        struct A {
+            my_int a;
+        };
+        inline uint32_t take_a(A a) {
+            return a.a;
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A {
+            a: 32,
+        };
+        assert_eq!(ffi::take_a(a), 32);
+    };
+    run_test("", hdr, rs, &["take_a"], &["A"]);
+}
+
+#[test]
+fn test_cint_in_pod_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        struct A {
+            int a;
+        };
+        inline uint32_t take_a(A a) {
+            return a.a;
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::A {
+            a: 32,
+        };
+        assert_eq!(ffi::take_a(a), 32);
+    };
+    run_test("", hdr, rs, &["take_a"], &["A"]);
+}
+
+#[test]
+fn test_string_in_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        struct A {
+            std::string a;
+        };
+        inline A make_a(std::string b) {
+            A bob;
+            bob.a = b;
+            return bob;
+        }
+        inline uint32_t take_a(A a) {
+            return a.a.size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
+    };
+    run_test("", hdr, rs, &["make_a", "take_a"], &[]);
+}
+
+#[test]
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+fn test_up_in_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        struct A {
+            std::unique_ptr<std::string> a;
+        };
+        inline A make_a(std::string b) {
+            A bob;
+            bob.a = std::make_unique<std::string>(b);
+            return bob;
+        }
+        inline uint32_t take_a(A a) {
+            return a.a->size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
+    };
+    run_test("", hdr, rs, &["make_a", "take_a"], &[]);
+}
+
+#[test]
+fn test_typedef_to_std_in_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        typedef std::string my_string;
+        struct A {
+            my_string a;
+        };
+        inline A make_a(std::string b) {
+            A bob;
+            bob.a = b;
+            return bob;
+        }
+        inline uint32_t take_a(A a) {
+            return a.a.size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
+    };
+    run_test("", hdr, rs, &["make_a", "take_a"], &[]);
+}
+
+#[test]
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+fn test_typedef_to_up_in_struct() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <memory>
+        typedef std::unique_ptr<std::string> my_string;
+        struct A {
+            my_string a;
+        };
+        inline A make_a(std::string b) {
+            A bob;
+            bob.a = std::make_unique<std::string>(b);
+            return bob;
+        }
+        inline uint32_t take_a(A a) {
+            return a.a->size();
+        }
+    "};
+    let rs = quote! {
+        use ffi::ToCppString;
+        assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
+    };
+    run_test("", hdr, rs, &["make_a", "take_a"], &[]);
+}
+
+#[test]
+fn test_float() {
+    let hdr = indoc! {"
+    inline float daft(float a) { return a; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::daft(34.0f32), 34.0f32);
+    };
+    run_test("", hdr, rs, &["daft"], &[]);
+}
+
+#[test]
+fn test_double() {
+    let hdr = indoc! {"
+    inline double daft(double a) { return a; }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::daft(34.0f64), 34.0f64);
+    };
+    run_test("", hdr, rs, &["daft"], &[]);
+}
+
+#[test]
+fn test_issues_217_222() {
+    let hdr = indoc! {"
+    #include <string>
+    #include <cstdint>
+    #include <cstddef>
+
+    template <typename STRING_TYPE> class BasicStringPiece {
+        public:
+         typedef size_t size_type;
+         typedef typename STRING_TYPE::traits_type traits_type;
+         typedef typename STRING_TYPE::value_type value_type;
+         typedef const value_type* pointer;
+         typedef const value_type& reference;
+         typedef const value_type& const_reference;
+         typedef ptrdiff_t difference_type;
+         typedef const value_type* const_iterator;
+         typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+         static const size_type npos;
+    };
+
+    template<typename CHAR>
+    class Replacements {
+     public:
+      Replacements() {
+      }
+      void SetScheme(const CHAR*) {
+      }
+      uint16_t a;
+    };
+
+    struct Component {
+        uint16_t a;
+    };
+
+    template <typename STR>
+    class StringPieceReplacements : public Replacements<typename STR::value_type> {
+        private:
+         using CharT = typename STR::value_type;
+         using StringPieceT = BasicStringPiece<STR>;
+         using ParentT = Replacements<CharT>;
+         using SetterFun = void (ParentT::*)(const CharT*, const Component&);
+         void SetImpl(SetterFun, StringPieceT) {
+        }
+        public:
+        void SetSchemeStr(const CharT* str) { SetImpl(&ParentT::SetScheme, str); }
+    };
+
+    class GURL {
+        public:
+        typedef StringPieceReplacements<std::string> UrlReplacements;
+        GURL() {}
+        GURL ReplaceComponents(const Replacements<char>&) const {
+            return GURL();
+        }
+        uint16_t a;
+    };
+    "};
+    let rs = quote! {
+        ffi::GURL::new().within_unique_ptr();
+    };
+    // The block! directives here are to avoid running into
+    // https://github.com/rust-lang/rust-bindgen/pull/1975
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate!("GURL") block!("StringPiece") block!("Replacements") },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+#[ignore] // https://github.com/rust-lang/rust-bindgen/pull/1975, https://github.com/google/autocxx/issues/106
+fn test_dependent_qualified_type() {
+    let hdr = indoc! {"
+    #include <stddef.h>
+    struct MyString {
+        typedef char value_type;
+    };
+    template<typename T> struct MyStringView {
+        typedef typename T::value_type view_value_type;
+        const view_value_type* start;
+        size_t length;
+    };
+    const char* HELLO = \"hello\";
+    inline MyStringView<MyString> make_string_view() {
+        MyStringView<MyString> r;
+        r.start = HELLO;
+        r.length = 2;
+        return r;
+    }
+    inline size_t take_string_view(const MyStringView<MyString>& bit) {
+        return bit.length;
+    }
+    "};
+    let rs = quote! {
+        let sv = ffi::make_string_view();
+        assert_eq!(ffi::take_string_view(sv.as_ref().unwrap()), 2);
+    };
+    run_test("", hdr, rs, &["take_string_view", "make_string_view"], &[]);
+}
+
+#[test]
+fn test_simple_dependent_qualified_type() {
+    // bindgen seems to cope with this case just fine
+    let hdr = indoc! {"
+    #include <stddef.h>
+    #include <stdint.h>
+    struct MyString {
+        typedef char value_type;
+    };
+    template<typename T> struct MyStringView {
+        typedef typename T::value_type view_value_type;
+        const view_value_type* start;
+        size_t length;
+    };
+    typedef MyStringView<MyString>::view_value_type MyChar;
+    inline MyChar make_char() {
+        return 'a';
+    }
+    inline uint32_t take_char(MyChar c) {
+        return static_cast<unsigned char>(c);
+    }
+    "};
+    let rs = quote! {
+        let c = ffi::make_char();
+        assert_eq!(ffi::take_char(c), 97);
+    };
+    run_test("", hdr, rs, &["make_char", "take_char"], &[]);
+}
+
+#[test]
+fn test_ignore_dependent_qualified_type() {
+    let hdr = indoc! {"
+    #include <stddef.h>
+    struct MyString {
+        typedef char value_type;
+    };
+    template<typename T> struct MyStringView {
+        typedef typename T::value_type view_value_type;
+        const view_value_type* start;
+        size_t length;
+    };
+    MyStringView<MyString> make_string_view();
+    struct B {
+        B() {}
+        inline size_t take_string_view(const MyStringView<MyString> bit) {
+            return bit.length;
+        }
+    };
+    "};
+    let cpp = indoc! {"
+    const char* HELLO = \"hello\";
+    MyStringView<MyString> make_string_view() {
+        MyStringView<MyString> r;
+        r.start = HELLO;
+        r.length = 2;
+        return r;
+    }
+    "};
+    let rs = quote! {
+        ffi::B::new().within_unique_ptr();
+    };
+    run_test(cpp, hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_ignore_dependent_qualified_type_reference() {
+    let hdr = indoc! {"
+    #include <stddef.h>
+    struct MyString {
+        typedef char value_type;
+    };
+    template<typename T> struct MyStringView {
+        typedef typename T::value_type view_value_type;
+        const view_value_type* start;
+        size_t length;
+    };
+    MyStringView<MyString> make_string_view();
+    struct B {
+        B() {}
+        inline size_t take_string_view(const MyStringView<MyString>& bit) {
+            return bit.length;
+        }
+    };
+    "};
+    let cpp = indoc! {"
+    const char* HELLO = \"hello\";
+    MyStringView<MyString> make_string_view() {
+        MyStringView<MyString> r;
+        r.start = HELLO;
+        r.length = 2;
+        return r;
+    }
+    "};
+    let rs = quote! {
+        ffi::B::new().within_unique_ptr();
+    };
+    run_test(cpp, hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_specialization() {
+    let hdr = indoc! {"
+    #include <stddef.h>
+    #include <stdint.h>
+    #include <string>
+    #include <type_traits>
+
+    template <typename T, bool = std::is_trivially_destructible<T>::value>
+    struct OptionalStorageBase {
+        T value_;
+    };
+
+    template <typename T,
+    bool = std::is_trivially_copy_constructible<T>::value,
+    bool = std::is_trivially_move_constructible<T>::value>
+    struct OptionalStorage : OptionalStorageBase<T> {};
+
+    template <typename T>
+    struct OptionalStorage<T,
+                       true /* trivially copy constructible */,
+                       false /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+    };
+
+    template <typename T>
+    struct OptionalStorage<T,
+                       false /* trivially copy constructible */,
+                       true /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+    };
+
+    template <typename T>
+    struct OptionalStorage<T,
+                       true /* trivially copy constructible */,
+                       true /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+    };
+
+    template <typename T>
+    class OptionalBase {
+    private:
+        OptionalStorage<T> storage_;
+    };
+
+    template <typename T>
+    class Optional : public OptionalBase<T> {
+
+    };
+
+    struct B {
+        B() {}
+        void take_optional(Optional<std::string>) {}
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {
+        ffi::B::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_private_constructor_make_unique() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    struct A {
+    private:
+        A() {};
+    public:
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/266
+fn test_take_array() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    uint32_t take_array(const uint32_t a[4]) {
+        return a[0] + a[2];
+    }
+    "};
+    let rs = quote! {
+        let c: [u32; 4usize] = [ 10, 20, 30, 40 ];
+        let c = c as *const [_];
+        assert_eq!(ffi::take_array(&c), 40);
+    };
+    run_test("", hdr, rs, &["take_array"], &[]);
+}
+
+#[test]
+fn test_take_array_in_struct() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    struct data {
+        char a[4];
+    };
+    uint32_t take_array(const data a) {
+        return a.a[0] + a.a[2];
+    }
+    "};
+    let rs = quote! {
+        let c = ffi::data { a: [ 10, 20, 30, 40 ] };
+        assert_eq!(ffi::take_array(c), 40);
+    };
+    run_test("", hdr, rs, &["take_array"], &["data"]);
+}
+
+#[test]
+fn test_union_ignored() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    union A {
+        uint32_t a;
+        float b;
+    };
+    struct B {
+        B() :a(1) {}
+        uint32_t take_union(A) const {
+            return 3;
+        }
+        uint32_t get_a() const { return 2; }
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {
+        let b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.get_a(), 2);
+    };
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_double_underscores_ignored() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    struct __FOO {
+        uint32_t a;
+    };
+    struct B {
+        B() :a(1) {}
+        uint32_t take_foo(__FOO) const {
+            return 3;
+        }
+        void do__something() const { }
+        uint32_t get_a() const { return 2; }
+        uint32_t a;
+    };
+
+    struct __default { __default() = default; };
+    struct __destructor { ~__destructor() = default; };
+    struct __copy { __copy(const __copy&) = default; };
+    struct __copy_operator { __copy_operator &operator=(const __copy_operator&) = default; };
+    struct __move { __move(__move&&) = default; };
+    struct __move_operator { __move_operator &operator=(const __move_operator&) = default; };
+    "};
+    let rs = quote! {
+        let b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.get_a(), 2);
+    };
+    run_test(
+        "",
+        hdr,
+        rs,
+        &[
+            "B",
+            "__default",
+            "__destructor",
+            "__copy",
+            "__copy_operator",
+            "__move",
+            "__move_operator",
+        ],
+        &[],
+    );
+}
+
+// This test fails on Windows gnu but not on Windows msvc
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[test]
+fn test_double_underscore_typedef_ignored() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    typedef int __int32_t;
+    typedef __int32_t __darwin_pid_t;
+    typedef __darwin_pid_t pid_t;
+    struct B {
+        B() :a(1) {}
+        uint32_t take_foo(pid_t) const {
+            return 3;
+        }
+        uint32_t get_a() const { return 2; }
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {
+        let b = ffi::B::new().within_unique_ptr();
+        assert_eq!(b.get_a(), 2);
+    };
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_double_underscores_fn_namespace() {
+    let hdr = indoc! {"
+    namespace __B {
+        inline void a() {}
+    };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_typedef_to_ptr_is_marked_unsafe() {
+    let hdr = indoc! {"
+    struct _xlocalefoo; /* forward reference */
+    typedef struct _xlocalefoo * locale_tfoo;
+    extern \"C\" {
+        locale_tfoo duplocalefoo(locale_tfoo);
+    }
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["duplocalefoo"], &[]);
+}
+
+#[test]
+fn test_issue_264() {
+    let hdr = indoc! {"
+    namespace a {
+        typedef int b;
+        //inline namespace c {}
+        template <typename> class aa;
+        inline namespace c {
+        template <typename d, typename = d, typename = aa<d>> class e;
+        }
+        typedef e<char> f;
+        template <typename g, typename, template <typename> typename> struct h {
+          using i = g;
+        };
+        template <typename g, template <typename> class k> using j = h<g, void, k>;
+        template <typename g, template <typename> class k>
+        using m = typename j<g, k>::i;
+        template <typename> struct l { typedef b ab; };
+        template <typename p> class aa {
+        public:
+          typedef p n;
+        };
+        struct r {
+          template <typename p> using o = typename p::c;
+        };
+        template <typename ad> struct u : r {
+          typedef typename ad::n n;
+          using ae = m<n, o>;
+          template <typename af, typename> struct v { using i = typename l<f>::ab; };
+          using ab = typename v<ad, ae>::i;
+        };
+        } // namespace a
+        namespace q {
+        template <typename ad> struct w : a::u<ad> {};
+        } // namespace q
+        namespace a {
+        inline namespace c {
+        template <typename, typename, typename ad> class e {
+          typedef q::w<ad> s;
+        public:
+          typedef typename s::ab ab;
+        };
+        } // namespace c
+        } // namespace a
+        namespace ag {
+        namespace ah {
+        typedef a::f::ab t;
+        class ai {
+        public:
+          t aj;
+        };
+        class al;
+        namespace am {
+        class an {
+        public:
+          void ao(ai);
+        };
+        } // namespace am
+        class ap {
+        public:
+          al aq();
+        };
+        class ar {
+        public:
+          am::an as;
+        };
+        class al {
+        public:
+          ar at;
+        };
+        struct au {
+          ap av;
+        };
+        } // namespace ah
+        } // namespace ag
+        namespace operations_research {
+        class aw {
+        public:
+          ag::ah::au ax;
+        };
+        class Solver {
+        public:
+          aw ay;
+        };
+        } // namespace operations_research
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(&["operations_research::Solver"], &[], None),
+        make_cpp17_adder(),
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_unexpected_use() {
+    // https://github.com/google/autocxx/issues/303
+    let hdr = indoc! {"
+        typedef int a;
+        namespace b {
+        namespace c {
+        enum d : a;
+        }
+        } // namespace b
+        namespace {
+        using d = b::c::d;
+        }
+        namespace content {
+        class RenderFrameHost {
+        public:
+            RenderFrameHost() {}
+        d e;
+        };
+        } // namespace content
+        "};
+    let rs = quote! {
+        let _ = ffi::content::RenderFrameHost::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["content::RenderFrameHost"], &[]);
+}
+
+#[test]
+fn test_get_pure_virtual() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        class A {
+        public:
+            virtual ~A() {}
+            virtual uint32_t get_val() const = 0;
+        };
+        class B : public A {
+        public:
+            virtual uint32_t get_val() const { return 3; }
+        };
+        const B b;
+        inline const A* get_a() { return &b; };
+    "};
+    let rs = quote! {
+        let a = ffi::get_a();
+        let a_ref = unsafe { a.as_ref() }.unwrap();
+        assert_eq!(a_ref.get_val(), 3);
+    };
+    run_test("", hdr, rs, &["A", "get_a"], &[]);
+}
+
+#[test]
+fn test_abstract_class_no_make_unique() {
+    // We shouldn't generate a new().within_unique_ptr() for abstract classes.
+    // The test is successful if the bindings compile, i.e. if autocxx doesn't
+    // attempt to instantiate the class.
+    let hdr = indoc! {"
+        class A {
+        public:
+            A() {}
+            virtual ~A() {}
+            virtual void foo() const = 0;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_derived_abstract_class_no_make_unique() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            A();
+            virtual ~A() {}
+            virtual void foo() const = 0;
+        };
+
+        class B : public A {
+        public:
+            B();
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_recursive_derived_abstract_class_no_make_unique() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            A() {}
+            virtual ~A() {}
+            virtual void foo() const = 0;
+        };
+
+        class B : public A {
+        public:
+            B() {};
+        };
+
+        class C : public B {
+        public:
+            C() {};
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B", "C"], &[]);
+}
+
+#[test]
+fn test_derived_abstract_class_with_no_allowlisting_no_make_unique() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            A();
+            virtual ~A() {}
+            virtual void foo() const = 0;
+        };
+
+        class B : public A {
+        public:
+            B();
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["B"], &[]);
+}
+
+#[test]
+fn test_vector_of_pointers() {
+    // Just ensures the troublesome API is ignored
+    let hdr = indoc! {"
+        #include <vector>
+        namespace operations_research {
+        class a;
+        class Solver {
+        public:
+          struct b c(std::vector<a *>);
+        };
+        class a {};
+        } // namespace operations_research
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["operations_research::Solver"], &[]);
+}
+
+#[test]
+fn test_vec_and_up_of_primitives() {
+    let hdr = indoc! {"
+        #include <vector>
+        #include <memory>
+        #include <cstdint>
+        class Value {
+        public:
+            Value(std::vector<uint32_t>) {} // OK
+            Value(std::unique_ptr<uint32_t>) {} // should be ignored
+            Value(std::vector<int>) {} // should be ignored
+            Value(std::unique_ptr<int>) {} // should be ignored
+            Value(std::vector<char>) {} // should be ignored
+            Value(std::unique_ptr<char>) {} // should be ignored
+            Value(std::vector<float>) {} // OK
+            Value(std::unique_ptr<float>) {} // should be ignored
+            Value(std::vector<bool>) {} // should be ignored
+            Value(std::unique_ptr<bool>) {} // should be ignored
+            Value(std::vector<size_t>) {} // OK
+            Value(std::unique_ptr<size_t>) {} // should be ignored
+        };
+        inline std::vector<uint32_t> make_vec_uint32_t() {
+            std::vector<uint32_t> a;
+            return a;
+        }
+        inline std::vector<float> make_vec_float() {
+            std::vector<float> a;
+            return a;
+        }
+        inline std::vector<size_t> make_vec_size_t() {
+            std::vector<size_t> a;
+            return a;
+        }
+    "};
+    let rs = quote! {
+        ffi::Value::new(ffi::make_vec_uint32_t()).within_box();
+        ffi::Value::new6(ffi::make_vec_float()).within_box();
+        ffi::Value::new10(ffi::make_vec_size_t()).within_box();
+    };
+    run_test(
+        "",
+        hdr,
+        rs,
+        &[
+            "Value",
+            "make_vec_uint32_t",
+            "make_vec_float",
+            "make_vec_size_t",
+        ],
+        &[],
+    );
+}
+
+#[test]
+fn test_pointer_to_pointer() {
+    // Just ensures the troublesome API is ignored
+    let hdr = indoc! {"
+        namespace operations_research {
+        class a;
+        class Solver {
+        public:
+          struct b c(a **);
+        };
+        class a {};
+        } // namespace operations_research
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["operations_research::Solver"], &[]);
+}
+
+#[test]
+fn test_defines_effective() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #ifdef FOO
+        inline uint32_t a() { return 4; }
+        #endif
+    "};
+    let rs = quote! {
+        ffi::a();
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate!("a") },
+        make_clang_arg_adder(&["-DFOO"]),
+        None,
+        None,
+    );
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/227
+fn test_function_pointer_template() {
+    let hdr = indoc! {"
+        typedef int a;
+        namespace std {
+        template <typename> class b;
+        }
+        typedef a c;
+        namespace operations_research {
+        class d;
+        class Solver {
+        public:
+            typedef std::b<c()> IndexEvaluator3;
+            d e(IndexEvaluator3);
+        };
+        class d {};
+        } // namespace operations_research
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["operations_research::Solver"], &[]);
+}
+
+#[test]
+fn test_cvoid() {
+    let hdr = indoc! {"
+        #include <memory>
+        #include <cstdint>
+        inline void* a() {
+            return static_cast<void*>(new int(3));
+        }
+        inline uint32_t b(void* p) {
+            int* p_int = static_cast<int*>(p);
+            auto val = *p_int;
+            delete p_int;
+            return val;
+        }
+    "};
+    let rs = quote! {
+        let ptr = ffi::a();
+        let res = unsafe { ffi::b(ptr) };
+        assert_eq!(res, 3);
+    };
+    run_test("", hdr, rs, &["a", "b"], &[]);
+}
+
+#[test]
+fn test_c_schar() {
+    let hdr = indoc! {"
+        inline signed char a() {
+            return 8;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::a(), 8);
+    };
+    run_test("", hdr, rs, &["a"], &[]);
+}
+
+#[test]
+fn test_c_uchar() {
+    let hdr = indoc! {"
+        inline unsigned char a() {
+            return 8;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::a(), 8);
+    };
+    run_test("", hdr, rs, &["a"], &[]);
+}
+
+#[test]
+fn test_c_ulonglong() {
+    // We don't test all the different variable-length integer types which we populate.
+    // If one works, they probably all do. Hopefully.
+    let hdr = indoc! {"
+        inline unsigned long long a() {
+            return 8;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::a(), autocxx::c_ulonglong(8));
+    };
+    run_test("", hdr, rs, &["a"], &[]);
+}
+
+#[test]
+fn test_string_transparent_function() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+        inline uint32_t take_string(std::string a) { return a.size(); }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::take_string("hello"), 5);
+    };
+    run_test("", hdr, rs, &["take_string"], &[]);
+}
+
+#[test]
+fn test_string_transparent_method() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+        struct A {
+            A() {}
+            inline uint32_t take_string(std::string a) const { return a.size(); }
+        };
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        assert_eq!(a.take_string("hello"), 5);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_string_transparent_static_method() {
+    let hdr = indoc! {"
+        #include <string>
+        #include <cstdint>
+        struct A {
+            A() {}
+            static inline uint32_t take_string(std::string a) { return a.size(); }
+        };
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::A::take_string("hello"), 5);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/490
+fn test_issue_490() {
+    let hdr = indoc! {"
+        typedef int a;
+        typedef long unsigned size_t;
+        namespace std {
+        namespace {
+        using ::size_t;
+        template <class b, b c> struct g { static const b value = c; };
+        template <bool d> using e = g<bool, d>;
+        typedef e<true> true_type;
+        template <size_t, size_t> struct ag {};
+        template <class b> typename b ::h move();
+        template <class> class allocator;
+        template <class> class vector;
+        } // namespace
+        } // namespace std
+        void *operator new(size_t, void *);
+        namespace std {
+        namespace {
+        template <class> struct iterator;
+        template <class b, class> struct ay { using h = b *; };
+        template <class b> struct bj { b bk; };
+        template <class bm, class> class bn : bj<bm> {};
+        template <class b, class i = b> class unique_ptr {
+        typedef i bp;
+        typedef typename ay<b, bp>::h bh;
+        bn<bh, bp> bq;
+
+        public:
+        unique_ptr();
+        unique_ptr(bh);
+        bh get() const;
+        bh release();
+        };
+        template <class = void> struct bt;
+        } // namespace
+        } // namespace std
+        typedef a bv;
+        namespace absl {
+        template <typename ce> class cj {
+        public:
+        using bh = ce *;
+        using iterator = bh;
+        };
+        namespace j {
+        template <class ce> struct cp {
+        using k = ce;
+        using cq = std::bt<>;
+        };
+        template <class ce> using cr = typename cp<ce>::k;
+        template <class ce> using cs = typename cp<ce>::cq;
+        template <class, class, class, class> class ct {
+        public:
+        class iterator {};
+        class cu {
+            cu(iterator);
+            iterator cv;
+        };
+        };
+        template <typename> struct cw;
+        } // namespace j
+        template <class ce, class k = j::cr<ce>, class cq = j::cs<ce>,
+                class cx = std::allocator<ce>>
+        class cy : public j::ct<j::cw<ce>, k, cq, cx> {};
+        } // namespace absl
+        namespace cz {
+        template <typename da> class db { std::ag<sizeof(a), alignof(da)> c; };
+        } // namespace cz
+        namespace spanner {
+        class l;
+        class ColumnList {
+        public:
+        typedef absl::cj<l>::iterator iterator;
+        iterator begin();
+        };
+        class dd {
+        union {
+            cz::db<absl::cy<bv>::cu> e;
+        };
+        };
+        class Row {
+        public:
+        bool f(dd);
+        };
+        } // namespace spanner
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["spanner::Row", "spanner::ColumnList"], &[]);
+}
+
+#[test]
+fn test_immovable_object() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            A();
+            A(A&&) = delete;
+        };
+
+        class B{
+        public:
+            B();
+            B(const B&) = delete;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_struct_with_reference() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <utility>
+        struct A {
+            uint32_t a;
+        };
+        struct B {
+            B(const A& param) : a(param) {}
+            const A& a;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_struct_with_rvalue() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <utility>
+        struct A {
+            uint32_t a;
+        };
+        struct B {
+            B(A&& param) : a(std::move(param)) {}
+            A&& a;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_immovable_nested_object() {
+    let hdr = indoc! {"
+        struct C {
+            class A {
+            public:
+                A();
+                A(A&&) = delete;
+            };
+
+            class B{
+            public:
+                B();
+                B(const B&) = delete;
+            };
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["C_A", "C_B"], &[]);
+}
+
+#[test]
+fn test_type_called_type() {
+    let hdr = indoc! {"
+        namespace a {
+            template<int _Len>
+            struct b
+            {
+                union type
+                {
+                    unsigned char __data[_Len];
+                    struct foo {
+                        int a;
+                    };
+                };
+            };
+        }
+        inline void take_type(a::b<4>::type) {}
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["take_type"], &[]);
+}
+
+#[test]
+fn test_bridge_conflict_ty() {
+    let hdr = indoc! {"
+        namespace a {
+            struct Key { int a; };
+        }
+        namespace b {
+            struct Key { int a; };
+        }
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
+}
+
+#[test]
+fn test_bridge_conflict_ty_fn() {
+    let hdr = indoc! {"
+        namespace a {
+            struct Key { int a; };
+        }
+        namespace b {
+            inline void Key() {}
+        }
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
+}
+
+#[test]
+fn test_issue_506() {
+    let hdr = indoc! {"
+        namespace std {
+            template <class, class> class am;
+            typedef am<char, char> an;
+        } // namespace std
+        namespace be {
+            class bf {
+            virtual std::an bg() = 0;
+            };
+            class bh : bf {};
+        } // namespace be
+        namespace spanner {
+            class Database;
+            class Row {
+            public:
+            Row(be::bh *);
+            };
+        } // namespace spanner
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["spanner::Database", "spanner::Row"], &[]);
+}
+
+#[test]
+fn test_private_inheritance() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            void foo() {}
+            int a;
+        };
+        class B : A {
+        public:
+            void bar() {}
+            int b;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A", "B"], &[]);
+}
+
+#[test]
+fn test_error_generated_for_static_data() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct A {
+            A() {}
+            uint32_t a;
+        };
+        static A FOO = A();
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate!("FOO")},
+        None,
+        Some(make_error_finder("FOO")),
+        None,
+    );
+}
+
+#[test]
+fn test_error_generated_for_array_dependent_function() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <functional>
+        inline void take_func(std::function<bool(const uint32_t number)>) {
+        }
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate! ("take_func")},
+        None,
+        Some(make_error_finder("take_func")),
+        None,
+    );
+}
+
+#[test]
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
+fn test_error_generated_for_array_dependent_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <functional>
+        struct A {
+            void take_func(std::function<bool(const uint32_t number)>) {
+            }
+        };
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate! ("A")},
+        None,
+        Some(make_string_finder(
+            ["take_func", "couldn't be generated"]
+                .map(|s| s.to_string())
+                .to_vec(),
+        )),
+        None,
+    );
+}
+
+#[test]
+fn test_error_generated_for_pod_with_nontrivial_destructor() {
+    // take_a is necessary here because cxx won't generate the required
+    // static assertions unless the type is actually used in some context
+    // where cxx needs to decide it's trivial or non-trivial.
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <functional>
+        struct A {
+            ~A() {}
+        };
+        inline void take_a(A) {}
+    "};
+    let rs = quote! {};
+    run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
+}
+
+#[test]
+fn test_error_generated_for_pod_with_nontrivial_move_constructor() {
+    // take_a is necessary here because cxx won't generate the required
+    // static assertions unless the type is actually used in some context
+    // where cxx needs to decide it's trivial or non-trivial.
+    let hdr = indoc! {"
+        #include <cstdint>
+        #include <functional>
+        struct A {
+            A() = default;
+            A(A&&) {}
+        };
+        inline void take_a(A) {}
+    "};
+    let rs = quote! {};
+    run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
+}
+
+#[test]
+fn test_double_destruction() {
+    let hdr = indoc! {"
+        #include <stdio.h>
+        #include <stdlib.h>
+        // A simple type to let Rust verify the destructor is run.
+        struct NotTriviallyDestructible {
+            NotTriviallyDestructible() = default;
+            NotTriviallyDestructible(const NotTriviallyDestructible&) = default;
+            NotTriviallyDestructible(NotTriviallyDestructible&&) = default;
+
+            ~NotTriviallyDestructible() {}
+        };
+
+        struct ExplicitlyDefaulted {
+            ExplicitlyDefaulted() = default;
+            ~ExplicitlyDefaulted() = default;
+
+            NotTriviallyDestructible flag;
+        };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut moveit_t = ffi::ExplicitlyDefaulted::new();
+        }
+    };
+    match do_run_test(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(
+            &[],
+            &["NotTriviallyDestructible", "ExplicitlyDefaulted"],
+            None,
+        ),
+        None,
+        None,
+        None,
+    ) {
+        Err(TestError::CppBuild(_)) => {} // be sure this fails due to a static_assert
+        // rather than some runtime problem
+        _ => panic!("Test didn't fail as expected"),
+    };
+}
+
+#[test]
+fn test_keyword_function() {
+    let hdr = indoc! {"
+        inline void move(int) {};
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["move_"], &[]);
+}
+
+#[test]
+fn test_keyword_method() {
+    let hdr = indoc! {"
+        struct A {
+            int a;
+            inline void move() {};
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_doc_passthru() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        /// Elephants!
+        struct A {
+            uint32_t a;
+        };
+        /// Giraffes!
+        struct B {
+            uint32_t a;
+        };
+        /// Rhinos!
+        inline uint32_t get_a() { return 3; }
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(&["A", "get_a"], &["B"], None),
+        None,
+        Some(make_string_finder(
+            ["Giraffes", "Elephants", "Rhinos"]
+                .map(|s| s.to_string())
+                .to_vec(),
+        )),
+        None,
+    );
+}
+
+#[test]
+fn test_closure() {
+    // Ensuring presence of this closure doesn't break other things
+    let hdr = indoc! {"
+    #include <functional>
+    #include <cstdint>
+
+    inline bool take_closure(std::function<bool(const uint32_t number)> fn) {
+        return fn(5);
+    }
+    inline uint32_t get_a() {
+        return 3;
+    }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::get_a(), 3);
+    };
+    run_test("", hdr, rs, &["get_a"], &[]);
+}
+
+#[test]
+fn test_multiply_nested_inner_type() {
+    let hdr = indoc! {"
+        struct Turkey {
+            struct Duck {
+                struct Hen {
+                    int wings;
+                };
+                struct HenWithDefault {
+                    HenWithDefault() = default;
+                    int wings;
+                };
+                struct HenWithDestructor {
+                    ~HenWithDestructor() = default;
+                    int wings;
+                };
+                struct HenWithCopy {
+                    HenWithCopy() = default;
+                    HenWithCopy(const HenWithCopy&) = default;
+                    int wings;
+                };
+                struct HenWithMove {
+                    HenWithMove() = default;
+                    HenWithMove(HenWithMove&&) = default;
+                    int wings;
+                };
+            };
+        };
+        "};
+    let rs = quote! {
+        ffi::Turkey_Duck_Hen::new().within_unique_ptr();
+        ffi::Turkey_Duck_HenWithDefault::new().within_unique_ptr();
+        ffi::Turkey_Duck_HenWithDestructor::new().within_unique_ptr();
+        ffi::Turkey_Duck_HenWithCopy::new().within_unique_ptr();
+        ffi::Turkey_Duck_HenWithMove::new().within_unique_ptr();
+
+        moveit! {
+            let hen = ffi::Turkey_Duck_Hen::new();
+            let moved_hen = autocxx::moveit::new::mov(hen);
+            let _copied_hen = autocxx::moveit::new::copy(moved_hen);
+
+            let hen = ffi::Turkey_Duck_HenWithDefault::new();
+            let moved_hen = autocxx::moveit::new::mov(hen);
+            let _copied_hen = autocxx::moveit::new::copy(moved_hen);
+
+            let _hen = ffi::Turkey_Duck_HenWithDestructor::new();
+
+            let hen = ffi::Turkey_Duck_HenWithCopy::new();
+            let _copied_hen = autocxx::moveit::new::copy(hen);
+
+            let hen = ffi::Turkey_Duck_HenWithMove::new();
+            let _moved_hen = autocxx::moveit::new::mov(hen);
+        }
+    };
+    run_test(
+        "",
+        hdr,
+        rs,
+        &[],
+        &[
+            "Turkey_Duck_Hen",
+            "Turkey_Duck_HenWithDefault",
+            "Turkey_Duck_HenWithDestructor",
+            "Turkey_Duck_HenWithCopy",
+            "Turkey_Duck_HenWithMove",
+        ],
+    );
+}
+
+#[test]
+fn test_underscored_namespace_for_inner_type() {
+    let hdr = indoc! {"
+        namespace __foo {
+            struct daft {
+                struct bob {
+                    int a;
+                };
+                int a;
+            };
+        }
+        inline void bar(__foo::daft::bob) {}
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["bar"], &[]);
+}
+
+#[test]
+fn test_blocklist_not_overly_broad() {
+    // This is a regression test. We used to block anything that starts with "rust" or "std",
+    // not just items in the "rust" and "std" namespaces. We therefore test that functions starting
+    // with "rust" or "std" get imported.
+    let hdr = indoc! {"
+    inline void rust_func() { }
+    inline void std_func() { }
+    "};
+    let rs = quote! {
+        ffi::rust_func();
+        ffi::std_func();
+    };
+    run_test("", hdr, rs, &["rust_func", "std_func"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/837
+fn test_ref_qualified_method() {
+    let hdr = indoc! {"
+        struct A {
+            void foo() & {}
+        };
+    "};
+    let rs = quote! {
+        A::new().within_unique_ptr().foo();
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[test]
+fn test_stringview() {
+    // Test that APIs using std::string_view do not otherwise cause errors.
+    let hdr = indoc! {"
+        #include <string_view>
+        #include <string>
+        void take_string_view(std::string_view) {}
+        std::string_view return_string_view(const std::string& a) { return std::string_view(a); }
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(&["take_string_view", "return_string_view"], &[], None),
+        make_cpp17_adder(),
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_include_cpp_alone() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t give_int() {
+            return 5;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        use autocxx::include_cpp;
+        include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("give_int")
+        }
+        fn main() {
+            assert_eq!(ffi::give_int(), 5);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_include_cpp_in_path() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t give_int() {
+            return 5;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+            autocxx::include_cpp! {
+                #hexathorpe include "input.h"
+                safety!(unsafe_ffi)
+                generate!("give_int")
+            }
+            fn main() {
+                assert_eq!(ffi::give_int(), 5);
+            }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_bitset() {
+    let hdr = indoc! {"
+        #include <cstddef>
+        template <size_t _N_words, size_t _Size>
+        class __bitset
+        {
+        public:
+            typedef size_t              __storage_type;
+            __storage_type __first_[_N_words];
+            inline bool all() {
+                return false;
+            }
+        };
+
+        template <size_t _Size>
+        class bitset
+            : private __bitset<_Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1, _Size>
+        {
+        public:
+            static const unsigned __n_words = _Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1;
+            typedef __bitset<__n_words, _Size> base;
+            bool all() const noexcept;
+        };
+
+
+        typedef bitset<1> mybitset;
+    "};
+
+    let rs = quote! {};
+
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_all!()
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_cint_vector() {
+    let hdr = indoc! {"
+        #include <vector>
+        #include <cstdint>
+        inline std::vector<int32_t> give_vec() {
+            return std::vector<int32_t> {1,2};
+        }
+    "};
+
+    let rs = quote! {
+        assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[1,2]);
+    };
+
+    run_test("", hdr, rs, &["give_vec"], &[]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/422
+fn test_int_vector() {
+    let hdr = indoc! {"
+        #include <vector>
+        std::vector<int> give_vec() {
+            return std::vector<int> {1,2};
+        }
+    "};
+
+    let rs = quote! {
+        assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]);
+    };
+
+    run_test("", hdr, rs, &["give_vec"], &[]);
+}
+
+#[test]
+fn test_size_t() {
+    let hdr = indoc! {"
+        #include <cstddef>
+        inline size_t get_count() { return 7; }
+    "};
+
+    let rs = quote! {
+        ffi::get_count();
+    };
+
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(&["get_count"], &[], None),
+        None,
+        Some(make_rust_code_finder(vec![
+            quote! {fn get_count() -> usize},
+        ])),
+        None,
+    );
+}
+
+#[test]
+fn test_deleted_function() {
+    // We shouldn't generate bindings for deleted functions.
+    // The test is successful if the bindings compile, i.e. if autocxx doesn't
+    // attempt to call the deleted function.
+    let hdr = indoc! {"
+        class A {
+        public:
+            void foo() = delete;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_ignore_move_constructor() {
+    let hdr = indoc! {"
+        class A {
+        public:
+            A() {}
+            A(A&&) {};
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_ignore_function_with_rvalue_ref() {
+    let hdr = indoc! {"
+        #include <string>
+
+        void moveme(std::string &&);
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["moveme"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_rvalue_from_up() {
+    let hdr = indoc! {"
+        #include <string>
+        struct A {
+            std::string a;
+        };
+        inline void take_a(A&&) {};
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        ffi::take_a(a);
+
+        let a2 = ffi::A::new().within_box();
+        ffi::take_a(a2);
+    };
+    run_test("", hdr, rs, &["A", "take_a"], &[]);
+}
+
+#[test]
+fn test_take_nonpod_rvalue_from_stack() {
+    let hdr = indoc! {"
+        #include <string>
+        struct A {
+            std::string a;
+        };
+        inline void take_a(A&&) {};
+    "};
+    let rs = quote! {
+        moveit! { let a = ffi::A::new() };
+        ffi::take_a(a);
+    };
+    run_test("", hdr, rs, &["A", "take_a"], &[]);
+}
+
+#[test]
+fn test_overloaded_ignored_function() {
+    // When overloaded functions are ignored during import, the placeholder
+    // functions generated for them should have unique names, just as they
+    // would have if they had been imported successfully.
+    // The test is successful if the bindings compile.
+    let hdr = indoc! {"
+        struct Blocked {};
+        class A {
+        public:
+            void take_blocked(Blocked);
+            void take_blocked(Blocked, int);
+        };
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate!("A")
+            block!("Blocked")
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_namespaced_constant() {
+    let hdr = indoc! {"
+        namespace A {
+            const int kConstant = 3;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::A::kConstant, 3);
+    };
+    run_test("", hdr, rs, &["A::kConstant"], &[]);
+}
+
+#[test]
+fn test_issue_470_492() {
+    let hdr = indoc! {"
+        namespace std {
+            template <bool, typename _Iftrue, typename _Iffalse> struct a;
+        }
+        template <typename> struct b;
+        template <typename d> struct c {
+            typedef std::a<b<d>::c, int, int> e;
+        };
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_all!()
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_no_impl() {
+    let hdr = indoc! {"
+        struct A {
+            int a;
+        };
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            exclude_impls!()
+            exclude_utilities!()
+            generate!("A")
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_generate_all() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t give_int() {
+            return 5;
+        }
+    "};
+    let rs = quote! {
+        assert_eq!(ffi::give_int(), 5);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_all!()
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_std_thing() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        namespace std {
+            struct A {
+                uint8_t a;
+            };
+        }
+        typedef char daft;
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_all!()
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_two_mods() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct A {
+            uint32_t a;
+        };
+        inline A give_a() {
+            A a;
+            a.a = 5;
+            return a;
+        }
+        inline uint32_t get_a(A a) {
+            return a.a;
+        }
+        struct B {
+            uint32_t a;
+        };
+        inline B give_b() {
+            B a;
+            a.a = 8;
+            return a;
+        }
+        inline uint32_t get_b(B a) {
+            return a.a;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        use autocxx::prelude::*;
+        include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("give_a")
+            generate!("get_a")
+        }
+        include_cpp! {
+            #hexathorpe include "input.h"
+            name!(ffi2)
+            generate!("give_b")
+            generate!("get_b")
+        }
+        fn main() {
+            let a = ffi::give_a().within_unique_ptr();
+            assert_eq!(ffi::get_a(a), 5);
+            let b = unsafe { ffi2::give_b().within_unique_ptr() };
+            assert_eq!(unsafe { ffi2::get_b(b) }, 8);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_manual_bridge() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline uint32_t give_int() {
+            return 5;
+        }
+        inline uint32_t give_int2() {
+            return 5;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        autocxx::include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("give_int")
+        }
+        #[cxx::bridge]
+        mod ffi2 {
+            unsafe extern "C++" {
+                include!("input.h");
+                fn give_int2() -> u32;
+            }
+        }
+        fn main() {
+            assert_eq!(ffi::give_int(), 5);
+            assert_eq!(ffi2::give_int2(), 5);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_manual_bridge_mixed_types() {
+    let hdr = indoc! {"
+        #include <memory>
+        struct A {
+            int a;
+        };
+        inline int take_A(const A& a) {
+            return a.a;
+        }
+        inline std::unique_ptr<A> give_A() {
+            auto a = std::make_unique<A>();
+            a->a = 5;
+            return a;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        use autocxx::prelude::*;
+        autocxx::include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("take_A")
+            generate!("A")
+        }
+        #[cxx::bridge]
+        mod ffi2 {
+            unsafe extern "C++" {
+                include!("input.h");
+                type A = crate::ffi::A;
+                fn give_A() -> UniquePtr<A>;
+            }
+        }
+        fn main() {
+            let a = ffi2::give_A();
+            assert_eq!(ffi::take_A(&a), autocxx::c_int(5));
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_extern_cpp_type_cxx_bridge() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct A {
+            A() : a(0) {}
+            int a;
+        };
+        inline void handle_a(const A&) {
+        }
+        inline A create_a() {
+            A a;
+            return a;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        use autocxx::prelude::*;
+        include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("handle_a")
+            generate!("create_a")
+            extern_cpp_opaque_type!("A", crate::ffi2::A)
+        }
+        #[cxx::bridge]
+        pub mod ffi2 {
+            unsafe extern "C++" {
+                include!("input.h");
+                type A;
+            }
+            impl UniquePtr<A> {}
+        }
+        fn main() {
+            let a = ffi::create_a();
+            ffi::handle_a(&a);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_extern_cpp_type_two_include_cpp() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct A {
+            A() : a(0) {}
+            int a;
+        };
+        enum B {
+            VARIANT,
+        };
+        inline void handle_a(const A&) {
+        }
+        inline A create_a(B) {
+            A a;
+            return a;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        pub mod base {
+            autocxx::include_cpp! {
+                #hexathorpe include "input.h"
+                name!(ffi2)
+                safety!(unsafe_ffi)
+                generate!("A")
+                generate!("B")
+            }
+            pub use ffi2::*;
+        }
+        pub mod dependent {
+            autocxx::include_cpp! {
+                #hexathorpe include "input.h"
+                safety!(unsafe_ffi)
+                generate!("handle_a")
+                generate!("create_a")
+                extern_cpp_type!("A", crate::base::A)
+                extern_cpp_type!("B", super::super::base::B)
+                pod!("B")
+            }
+            pub use ffi::*;
+        }
+        fn main() {
+            use autocxx::prelude::*;
+            let a = dependent::create_a(base::B::VARIANT).within_box();
+            dependent::handle_a(&a);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+#[ignore] // because we currently require UniquePtrTarget which this can't implement
+fn test_extern_cpp_type_manual() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct A {
+            int a;
+        };
+        inline void handle_a(const A& a) {
+        }
+        inline A create_a() {
+            A a;
+            return a;
+        }
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        autocxx::include_cpp! {
+            #hexathorpe include "input.h"
+            safety!(unsafe_ffi)
+            generate!("handle_a")
+            generate!("create_a")
+            extern_cpp_type!("A", crate::ffi2::A)
+        }
+        pub mod ffi2 {
+            use autocxx::cxx::{type_id, ExternType};
+            #[repr(C)]
+            pub struct A {
+                a: std::os::raw::c_int
+            }
+            unsafe impl ExternType for A {
+                type Kind = autocxx::cxx::kind::Opaque;
+                type Id = type_id!("A");
+            }
+
+        }
+        fn main() {
+            let a = ffi2::A { a: 3 };
+            ffi::handle_a(&a);
+        }
+    };
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+fn test_issue486() {
+    let hdr = indoc! {"
+        namespace a {
+            namespace spanner {
+                class Key;
+            }
+        } // namespace a
+        namespace spanner {
+            class Key {
+                public:
+                    bool b(a::spanner::Key &);
+            };
+        } // namespace spanner
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["spanner::Key"], &[]);
+}
+
+#[test]
+#[ignore]
+fn test_issue616() {
+    let hdr = indoc! {"
+        namespace N {
+            template <typename> class B{};
+            template <typename c> class C {
+            public:
+            using U = B<c>;
+            };
+            }
+            class A : N::C<A> {
+            U u;
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_shared_ptr() {
+    let hdr = indoc! {"
+        #include <memory>
+        struct A {
+            int a;
+        };
+        inline std::shared_ptr<A> make_shared_int() {
+            return std::make_shared<A>(A { 3 });
+        }
+        inline int take_shared_int(std::shared_ptr<A> a) {
+            return a->a;
+        }
+        inline std::weak_ptr<A> shared_to_weak(std::shared_ptr<A> a) {
+            return std::weak_ptr<A>(a);
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::make_shared_int();
+        assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
+        ffi::shared_to_weak(a).upgrade();
+    };
+    run_test(
+        "",
+        hdr,
+        rs,
+        &["make_shared_int", "take_shared_int", "shared_to_weak"],
+        &[],
+    );
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/799
+fn test_shared_ptr_const() {
+    let hdr = indoc! {"
+        #include <memory>
+        inline std::shared_ptr<const int> make_shared_int() {
+            return std::make_shared<const int>(3);
+        }
+        inline int take_shared_int(std::shared_ptr<const int> a) {
+            return *a;
+        }
+    "};
+    let rs = quote! {
+        let a = ffi::make_shared_int();
+        assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
+    };
+    run_test("", hdr, rs, &["make_shared_int", "take_shared_int"], &[]);
+}
+
+#[test]
+fn test_rust_reference() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    struct RustType;
+    inline uint32_t take_rust_reference(const RustType&) {
+        return 4;
+    }
+    "};
+    let rs = quote! {
+        let foo = RustType(3);
+        assert_eq!(ffi::take_rust_reference(&foo), 4);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate!("take_rust_reference")
+            extern_rust_type!(RustType)
+        },
+        None,
+        None,
+        Some(quote! {
+            pub struct RustType(i32);
+        }),
+    );
+}
+
+#[test]
+fn test_rust_reference_autodiscover() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    struct RustType;
+    inline uint32_t take_rust_reference(const RustType&) {
+        return 4;
+    }
+    "};
+    let rs = quote! {
+        let foo = RustType(3);
+        let result = ffi::take_rust_reference(&foo);
+        assert_eq!(result, 4);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {},
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            #[autocxx::extern_rust::extern_rust_type]
+            pub struct RustType(i32);
+        }),
+    );
+}
+
+#[test]
+fn test_pass_thru_rust_reference() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    struct RustType;
+    inline const RustType& pass_rust_reference(const RustType& a) {
+        return a;
+    }
+    "};
+    let rs = quote! {
+        let foo = RustType(3);
+        assert_eq!(ffi::pass_rust_reference(&foo).0, 3);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate!("pass_rust_reference")
+            extern_rust_type!(RustType)
+        },
+        None,
+        None,
+        Some(quote! {
+            pub struct RustType(i32);
+        }),
+    );
+}
+
+#[test]
+fn test_extern_rust_method() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        struct RustType;
+        uint32_t examine(const RustType& foo);
+    "};
+    let cxx = indoc! {"
+        uint32_t examine(const RustType& foo) {
+            return foo.get();
+        }"};
+    let rs = quote! {
+        let a = RustType(74);
+        assert_eq!(ffi::examine(&a), 74);
+    };
+    run_test_ex(
+        cxx,
+        hdr,
+        rs,
+        directives_from_lists(&["examine"], &[], None),
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            #[autocxx::extern_rust::extern_rust_type]
+            pub struct RustType(i32);
+            impl RustType {
+                #[autocxx::extern_rust::extern_rust_function]
+                pub fn get(&self) -> i32 {
+                    return self.0
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_rust_reference_no_autodiscover() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    struct RustType;
+    inline uint32_t take_rust_reference(const RustType&) {
+        return 4;
+    }
+    "};
+    let rs = quote! {
+        let foo = RustType(3);
+        let result = ffi::take_rust_reference(&foo);
+        assert_eq!(result, 4);
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        directives_from_lists(&["take_rust_reference"], &[], None),
+        None,
+        None,
+        Some(quote! {
+            #[autocxx::extern_rust::extern_rust_type]
+            pub struct RustType(i32);
+        }),
+    );
+}
+
+#[test]
+#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
+// TODO - replace make_clang_arg_adder with something that knows how to add an MSVC-suitable
+// directive for the cc build.
+fn test_cpp17() {
+    let hdr = indoc! {"
+        static_assert(__cplusplus >= 201703L, \"This file expects a C++17 compatible compiler.\");
+        inline void foo() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            ffi::foo();
+        },
+        quote! {
+            generate!("foo")
+        },
+        make_cpp17_adder(),
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_box() {
+    let hdr = indoc! {"
+        #include <cxx.h>
+        struct Foo;
+        inline void take_box(rust::Box<Foo>) {
+        }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            ffi::take_box(Box::new(Foo { a: "Hello".into() }))
+        },
+        quote! {
+            generate!("take_box")
+            extern_rust_type!(Foo)
+        },
+        None,
+        None,
+        Some(quote! {
+            pub struct Foo {
+                a: String,
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_box_via_extern_rust() {
+    let hdr = indoc! {"
+        #include <cxx.h>
+        struct Foo;
+        inline void take_box(rust::Box<Foo>) {
+        }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            ffi::take_box(Box::new(Foo { a: "Hello".into() }))
+        },
+        quote! {},
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            #[autocxx::extern_rust::extern_rust_type]
+            pub struct Foo {
+                a: String,
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_box_via_extern_rust_in_mod() {
+    let hdr = indoc! {"
+        #include <cxx.h>
+        struct Foo;
+        inline void take_box(rust::Box<Foo>) {
+        }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            ffi::take_box(Box::new(bar::Foo { a: "Hello".into() }))
+        },
+        quote! {},
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            mod bar {
+                #[autocxx::extern_rust::extern_rust_type]
+                pub struct Foo {
+                    pub a: String,
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_extern_rust_fn_simple() {
+    let cpp = indoc! {"
+        void foo() {
+            my_rust_fun();
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cxx.h>
+        inline void do_thing() {}
+    "};
+    run_test_ex(
+        cpp,
+        hdr,
+        quote! {
+            ffi::do_thing();
+        },
+        quote! {
+            generate!("do_thing")
+        },
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            #[autocxx::extern_rust::extern_rust_function]
+            fn my_rust_fun() {
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_extern_rust_fn_in_mod() {
+    let hdr = indoc! {"
+        #include <cxx.h>
+        inline void do_thing() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! {
+            generate!("do_thing")
+        },
+        Some(Box::new(EnableAutodiscover)),
+        None,
+        Some(quote! {
+            mod bar {
+                #[autocxx::extern_rust::extern_rust_function]
+                pub fn my_rust_fun() {
+
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_issue_956() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        inline void take_int(int&) {}
+        inline void take_uin16(uint16_t&) {}
+        inline void take_char16(char16_t &) {}
+    "};
+    run_test(
+        "",
+        hdr,
+        quote! {},
+        &["take_int", "take_uin16", "take_char16"],
+        &[],
+    );
+}
+
+#[test]
+fn test_extern_rust_fn_no_autodiscover() {
+    let hdr = indoc! {"
+        #include <cxx.h>
+    "};
+    let cpp = indoc! {"
+        void call_it() {
+            my_rust_fun();
+        }
+    "};
+    run_test_ex(
+        cpp,
+        hdr,
+        quote! {},
+        quote! {},
+        None,
+        None,
+        Some(quote! {
+            mod bar {
+                #[autocxx::extern_rust::extern_rust_function]
+                pub fn my_rust_fun() {
+
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_mut() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() = 0;
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&mut self) {
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_const() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) {
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_calls_impossible() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_expect_fail_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) {
+                    use ffi::Observer_supers;
+                    self.foo_super()
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_not_pub() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_expect_fail_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) {
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_ptr_param() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    struct A {
+        uint8_t a;
+    };
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo(const A*) const {};
+        virtual ~Observer() {}
+    };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("A")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                unsafe fn foo(&self, a: *const ffi::A) {
+                    use ffi::Observer_supers;
+                    self.foo_super(a)
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_return() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual uint32_t foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) -> u32 {
+                    4
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_passed_to_fn() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual uint32_t foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void take_observer(const Observer&) {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+            ffi::take_observer(o.borrow().as_ref());
+        },
+        quote! {
+            generate!("take_observer")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) -> u32 {
+                    4
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_derive_defaults() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual uint32_t foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void take_observer(const Observer&) {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            use autocxx::subclass::CppSubclassDefault;
+            let o = MyObserver::default_rust_owned();
+            ffi::take_observer(o.borrow().as_ref());
+        },
+        quote! {
+            generate!("take_observer")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            #[autocxx::subclass::subclass]
+            #[derive(Default)]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl ffi::Observer_methods for MyObserver {
+                fn foo(&self) -> u32 {
+                    4
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_non_pv_subclass_simple() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const {}
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_two_subclasses() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const {}
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+            let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserverA)
+            subclass!("Observer",MyObserverB)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserverA {
+                a: u32
+            }
+            impl Observer_methods for MyObserverA {
+            }
+            #[autocxx::subclass::subclass]
+            pub struct MyObserverB {
+                a: u32
+            }
+            impl Observer_methods for MyObserverB {
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_two_superclasses_with_same_name_method() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class ObserverA {
+    public:
+        ObserverA() {}
+        virtual void foo() const {}
+        virtual ~ObserverA() {}
+    };
+
+    class ObserverB {
+        public:
+            ObserverB() {}
+            virtual void foo() const {}
+            virtual ~ObserverB() {}
+        };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+            let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+        },
+        quote! {
+            generate!("bar")
+            subclass!("ObserverA",MyObserverA)
+            subclass!("ObserverB",MyObserverB)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::ObserverA_methods;
+            use ffi::ObserverB_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserverA {
+                a: u32
+            }
+            impl ObserverA_methods for MyObserverA {
+            }
+            #[autocxx::subclass::subclass]
+            pub struct MyObserverB {
+                a: u32
+            }
+            impl ObserverB_methods for MyObserverB {
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_protected_constructor() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    protected:
+        Observer() {}
+    public:
+        virtual void foo() const {}
+        virtual ~Observer() {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_protected_method() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer() {}
+        virtual void foo() const {}
+        virtual ~Observer() {}
+    protected:
+        virtual void baz() const {}
+    };
+    inline void bar() {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+            obs.borrow().foo();
+        },
+        quote! {
+            generate!("bar")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn baz(&self) {
+                }
+
+                fn foo(&self) {
+                    use ffi::Observer_supers;
+                    self.baz_super()
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_allocation_not_self_owned() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    extern \"C\" void mark_freed() noexcept;
+    extern \"C\" void mark_allocated() noexcept;
+
+    class TestObserver {
+    public:
+        TestObserver() {
+            mark_allocated();
+        }
+        virtual void a() const = 0;
+        virtual ~TestObserver() {
+            mark_freed();
+        }
+    };
+    inline void TriggerTestObserverA(const TestObserver& obs) {
+        obs.a();
+    }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+
+            // Test when owned by C++
+            let obs = MyTestObserver::new_cpp_owned(
+                MyTestObserver::new()
+            );
+            assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+            let obs_superclass = obs.as_ref().unwrap(); // &subclass
+            let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+            ffi::TriggerTestObserverA(obs_superclass);
+            assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
+            std::mem::drop(obs);
+            Lazy::force(&STATUS).lock().unwrap().a_called = false;
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+
+            // Test when owned by Rust
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::new()
+            );
+            //let cpp_peer_ptr = unsafe { obs.borrow_mut().peer_mut().get_unchecked_mut() as *mut ffi::MyTestObserverCpp };
+            assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+            ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
+            assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
+            Lazy::force(&STATUS).lock().unwrap().a_called = false;
+            std::mem::drop(obs);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+        },
+        quote! {
+            generate!("TriggerTestObserverA")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use once_cell::sync::Lazy;
+            use std::sync::Mutex;
+
+            use autocxx::subclass::CppSubclass;
+            use ffi::TestObserver_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyTestObserver {
+                data: ExternalEngine,
+            }
+            impl TestObserver_methods for MyTestObserver {
+                fn a(&self) {
+                    self.data.do_something();
+                }
+            }
+            impl MyTestObserver {
+                fn new() -> Self {
+                    Self {
+                        cpp_peer: Default::default(),
+                        data: ExternalEngine::default(),
+                    }
+                }
+            }
+
+            #[no_mangle]
+            pub fn mark_allocated() {
+                Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
+            }
+
+            #[no_mangle]
+            pub fn mark_freed() {
+                Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
+            }
+
+            #[derive(Default)]
+            struct Status {
+                cpp_allocated: bool,
+                rust_allocated: bool,
+                a_called: bool,
+            }
+
+            static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
+
+            pub struct ExternalEngine;
+
+            impl ExternalEngine {
+                fn do_something(&self) {
+                    Lazy::force(&STATUS).lock().unwrap().a_called = true;
+                }
+            }
+
+            impl Default for ExternalEngine {
+                fn default() -> Self {
+                    Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
+                    ExternalEngine
+                }
+            }
+
+            impl Drop for ExternalEngine {
+                fn drop(&mut self) {
+                    Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_allocation_self_owned() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    extern \"C\" void mark_freed() noexcept;
+    extern \"C\" void mark_allocated() noexcept;
+
+    class TestObserver {
+    public:
+        TestObserver() {
+            mark_allocated();
+        }
+        virtual void a() const = 0;
+        virtual ~TestObserver() {
+            mark_freed();
+        }
+    };
+    inline void TriggerTestObserverA(const TestObserver& obs) {
+        const_cast<TestObserver&>(obs).a();
+    }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+
+            // Test when owned by C++
+            let obs = MyTestObserver::new_cpp_owned(
+                MyTestObserver::new(false)
+            );
+            assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+            let obs_superclass = obs.as_ref().unwrap(); // &subclass
+            let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+
+            ffi::TriggerTestObserverA(obs_superclass);
+            assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
+            std::mem::drop(obs);
+            Lazy::force(&STATUS).lock().unwrap().a_called = false;
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+
+            // Test when owned by Rust
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::new(false)
+            );
+            assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+            ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
+
+            assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
+            Lazy::force(&STATUS).lock().unwrap().a_called = false;
+            std::mem::drop(obs);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+
+            // Test when self-owned
+            let obs = MyTestObserver::new_self_owned(
+                MyTestObserver::new(true)
+            );
+            let obs_superclass_ptr: *const ffi::TestObserver = obs.as_ref().borrow().as_ref();
+            // Retain just a pointer on the Rust side, so there is no Rust-side
+            // ownership.
+            std::mem::drop(obs);
+            assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+            assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
+            ffi::TriggerTestObserverA(unsafe { obs_superclass_ptr.as_ref().unwrap() });
+
+            assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
+        },
+        quote! {
+            generate!("TriggerTestObserverA")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use once_cell::sync::Lazy;
+            use std::sync::Mutex;
+
+            use autocxx::subclass::CppSubclass;
+            use autocxx::subclass::CppSubclassSelfOwned;
+            use ffi::TestObserver_methods;
+            #[autocxx::subclass::subclass(self_owned)]
+            pub struct MyTestObserver {
+                data: ExternalEngine,
+                self_owning: bool,
+            }
+            impl TestObserver_methods for MyTestObserver {
+                fn a(&self) {
+                    self.data.do_something();
+                    if self.self_owning {
+                        self.delete_self();
+                    }
+                }
+            }
+            impl MyTestObserver {
+                fn new(self_owning: bool) -> Self {
+                    Self {
+                        cpp_peer: Default::default(),
+                        data: ExternalEngine::default(),
+                        self_owning,
+                    }
+                }
+            }
+
+            #[no_mangle]
+            pub fn mark_allocated() {
+                Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
+            }
+
+            #[no_mangle]
+            pub fn mark_freed() {
+                Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
+            }
+
+            #[derive(Default)]
+            struct Status {
+                cpp_allocated: bool,
+                rust_allocated: bool,
+                a_called: bool,
+            }
+
+            static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
+
+            pub struct ExternalEngine;
+
+            impl ExternalEngine {
+                fn do_something(&self) {
+                    Lazy::force(&STATUS).lock().unwrap().a_called = true;
+                }
+            }
+
+            impl Default for ExternalEngine {
+                fn default() -> Self {
+                    Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
+                    ExternalEngine
+                }
+            }
+
+            impl Drop for ExternalEngine {
+                fn drop(&mut self) {
+                    Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_calls() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    extern \"C\" void mark_c_called() noexcept;
+    extern \"C\" void mark_d_called() noexcept;
+    extern \"C\" void mark_e_called() noexcept;
+    extern \"C\" void mark_f_called() noexcept;
+    extern \"C\" void mark_g_called() noexcept;
+    extern \"C\" void mark_h_called() noexcept;
+
+    class TestObserver {
+    public:
+        TestObserver() {}
+        virtual uint32_t a(uint32_t) const = 0;
+        virtual uint32_t b(uint32_t) = 0;
+        virtual uint32_t c(uint32_t) const { mark_c_called(); return 0; };
+        virtual uint32_t d(uint32_t) { mark_d_called(); return 0; };
+        virtual uint32_t e(uint32_t) const { mark_e_called(); return 0; };
+        virtual uint32_t f(uint32_t) { mark_f_called(); return 0; };
+        virtual uint32_t g(uint32_t) const { mark_g_called(); return 0; };
+        virtual uint32_t h(uint32_t) { mark_h_called(); return 0; };
+        virtual ~TestObserver() {}
+    };
+
+    extern TestObserver* obs;
+
+    inline void register_observer(TestObserver& a) {
+        obs = &a;
+    }
+    inline uint32_t call_a(uint32_t param) {
+        return obs->a(param);
+    }
+    inline uint32_t call_b(uint32_t param) {
+        return obs->b(param);
+    }
+    inline uint32_t call_c(uint32_t param) {
+        return obs->c(param);
+    }
+    inline uint32_t call_d(uint32_t param) {
+        return obs->d(param);
+    }
+    inline uint32_t call_e(uint32_t param) {
+        return obs->e(param);
+    }
+    inline uint32_t call_f(uint32_t param) {
+        return obs->f(param);
+    }
+    inline uint32_t call_g(uint32_t param) {
+        return obs->g(param);
+    }
+    inline uint32_t call_h(uint32_t param) {
+        return obs->h(param);
+    }
+    "};
+    run_test_ex(
+        "TestObserver* obs;",
+        hdr,
+        quote! {
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::default()
+            );
+            ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
+            assert_eq!(ffi::call_a(1), 2);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_b(1), 3);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_b_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_c(1), 4);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_c_called);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().super_c_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_d(1), 5);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_d_called);
+            assert!(!Lazy::force(&STATUS).lock().unwrap().super_d_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_e(1), 0);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_e_called);
+            assert!(Lazy::force(&STATUS).lock().unwrap().super_e_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_f(1), 0);
+            assert!(Lazy::force(&STATUS).lock().unwrap().sub_f_called);
+            assert!(Lazy::force(&STATUS).lock().unwrap().super_f_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_g(1), 0);
+            assert!(Lazy::force(&STATUS).lock().unwrap().super_g_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+
+            assert_eq!(ffi::call_h(1), 0);
+            assert!(Lazy::force(&STATUS).lock().unwrap().super_h_called);
+            *Lazy::force(&STATUS).lock().unwrap() = Default::default();
+        },
+        quote! {
+            generate!("register_observer")
+            generate!("call_a")
+            generate!("call_b")
+            generate!("call_c")
+            generate!("call_d")
+            generate!("call_e")
+            generate!("call_f")
+            generate!("call_g")
+            generate!("call_h")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use once_cell::sync::Lazy;
+            use std::sync::Mutex;
+
+            use autocxx::subclass::CppSubclass;
+            use ffi::TestObserver_methods;
+            #[autocxx::subclass::subclass]
+            #[derive(Default)]
+            pub struct MyTestObserver {
+            }
+            impl TestObserver_methods for MyTestObserver {
+
+                // a and b are pure virtual
+                fn a(&self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_a_called = true;
+                    param + 1
+                }
+                fn b(&mut self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_b_called = true;
+                    param + 2
+                }
+
+                // c and d we override the superclass
+                fn c(&self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_c_called = true;
+                    param + 3
+                }
+                fn d(&mut self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_d_called = true;
+                    param + 4
+                }
+
+                // e and f we call through to the superclass
+                fn e(&self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_e_called = true;
+                    self.peer().e_super(param)
+                }
+                fn f(&mut self, param: u32) -> u32 {
+                    Lazy::force(&STATUS).lock().unwrap().sub_f_called = true;
+                    self.peer_mut().f_super(param)
+                }
+
+                // g and h we do not do anything, so calls should only call
+                // the superclass
+            }
+
+            #[no_mangle]
+            pub fn mark_c_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_c_called = true;
+            }
+            #[no_mangle]
+            pub fn mark_d_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_d_called = true;
+            }
+            #[no_mangle]
+            pub fn mark_e_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_e_called = true;
+            }
+            #[no_mangle]
+            pub fn mark_f_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_f_called = true;
+            }
+            #[no_mangle]
+            pub fn mark_g_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_g_called = true;
+            }
+            #[no_mangle]
+            pub fn mark_h_called() {
+                Lazy::force(&STATUS).lock().unwrap().super_h_called = true;
+            }
+
+            #[derive(Default)]
+            struct Status {
+                super_c_called: bool,
+                super_d_called: bool,
+                super_e_called: bool,
+                super_f_called: bool,
+                super_g_called: bool,
+                super_h_called: bool,
+                sub_a_called: bool,
+                sub_b_called: bool,
+                sub_c_called: bool,
+                sub_d_called: bool,
+                sub_e_called: bool,
+                sub_f_called: bool,
+            }
+
+            static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
+        }),
+    );
+}
+
+#[test]
+fn test_cycle_nonpod_simple() {
+    let hdr = indoc! {"
+    #include <string>
+    struct NonPod {
+        std::string a;
+    };
+    inline NonPod make_non_pod(std::string a) {
+        NonPod p;
+        p.a = a;
+        return p;
+    }
+    inline NonPod call_n(NonPod param) {
+        return param;
+    }
+    "};
+    let rs = quote! {
+        let nonpod = ffi::make_non_pod("hello").within_unique_ptr();
+        ffi::call_n(nonpod).within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["NonPod", "make_non_pod", "call_n"], &[])
+}
+
+#[test]
+fn test_pv_subclass_types() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    #include <string>
+    #include <vector>
+
+    struct Fwd;
+    struct Pod {
+        uint32_t a;
+    };
+    struct NonPod {
+        std::string a;
+    };
+    class TestObserver {
+    public:
+        TestObserver() {}
+        virtual std::string s(std::string p) const { return p; }
+        virtual Pod p(Pod p) const { return p; }
+        virtual NonPod n(NonPod p) const { return p; }
+        virtual void f(const Fwd&) const { }
+        virtual std::vector<NonPod> v(std::vector<NonPod> v) const { return v; }
+        virtual const std::vector<NonPod>& vr(const std::vector<NonPod>& vr) const { return vr; }
+        virtual const std::vector<Fwd>& vfr(const std::vector<Fwd>& vfr) const { return vfr; }
+        virtual ~TestObserver() {}
+    };
+
+    extern TestObserver* obs;
+
+    inline void register_observer(TestObserver& a) {
+        obs = &a;
+    }
+    inline std::string call_s(std::string param) {
+        return obs->s(param);
+    }
+    inline Pod call_p(Pod param) {
+        return obs->p(param);
+    }
+    inline NonPod call_n(NonPod param) {
+        return obs->n(param);
+    }
+    inline NonPod make_non_pod(std::string a) {
+        NonPod p;
+        p.a = a;
+        return p;
+    }
+    "};
+    run_test_ex(
+        "TestObserver* obs;",
+        hdr,
+        quote! {
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::default()
+            );
+            ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
+            ffi::call_p(ffi::Pod { a: 3 });
+            ffi::call_s("hello");
+            ffi::call_n(ffi::make_non_pod("goodbye").within_unique_ptr());
+        },
+        quote! {
+            generate!("register_observer")
+            generate!("call_s")
+            generate!("call_n")
+            generate!("call_p")
+            generate!("NonPod")
+            generate!("make_non_pod")
+            generate_pod!("Pod")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::TestObserver_methods;
+            #[autocxx::subclass::subclass]
+            #[derive(Default)]
+            pub struct MyTestObserver {
+            }
+            impl TestObserver_methods for MyTestObserver {
+                fn s(&self, p: cxx::UniquePtr<cxx::CxxString>) -> cxx::UniquePtr<cxx::CxxString> {
+                    self.peer().s_super(p)
+                }
+
+                fn p(&self, p: ffi::Pod) -> ffi::Pod {
+                    self.peer().p_super(p)
+                }
+
+                fn n(&self, p: cxx::UniquePtr<ffi::NonPod>) -> cxx::UniquePtr<ffi::NonPod> {
+                    self.peer().n_super(p)
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_constructors() {
+    // Also tests a Rust-side subclass type which is an empty struct
+    let hdr = indoc! {"
+    #include <cstdint>
+    #include <string>
+
+    class TestObserver {
+    public:
+        TestObserver() {}
+        TestObserver(uint8_t) {}
+        TestObserver(std::string) {}
+        virtual void call() const { }
+        virtual ~TestObserver() {}
+    };
+
+    extern TestObserver* obs;
+
+    inline void register_observer(TestObserver& a) {
+        obs = &a;
+    }
+    inline void do_a_thing() {
+        return obs->call();
+    }
+    "};
+    run_test_ex(
+        "TestObserver* obs;",
+        hdr,
+        quote! {
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::default()
+            );
+            ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
+            ffi::do_a_thing();
+        },
+        quote! {
+            generate!("register_observer")
+            generate!("do_a_thing")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::prelude::*;
+            #[subclass]
+            #[derive(Default)]
+            pub struct MyTestObserver;
+            impl ffi::TestObserver_methods for MyTestObserver {
+                fn call(&self) {
+                    self.peer().call_super()
+                }
+            }
+            impl CppPeerConstructor<ffi::MyTestObserverCpp> for MyTestObserver {
+                fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> cxx::UniquePtr<ffi::MyTestObserverCpp> {
+                    ffi::MyTestObserverCpp::new1(peer_holder, 3u8).within_unique_ptr()
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_fancy_constructor() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    class Observer {
+    public:
+        Observer(uint8_t) {}
+        virtual uint32_t foo() const = 0;
+        virtual ~Observer() {}
+    };
+    inline void take_observer(const Observer&) {}
+    "};
+    run_test_expect_fail_ex(
+        "",
+        hdr,
+        quote! {
+            let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() }, ffi::MyObserverCpp::make_unique);
+            ffi::take_observer(o.borrow().as_ref());
+        },
+        quote! {
+            generate!("take_observer")
+            subclass!("Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            use ffi::Observer_methods;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl Observer_methods for MyObserver {
+                fn foo(&self) -> u32 {
+                    4
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_non_pv_subclass_overloads() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    #include <string>
+
+    class TestObserver {
+    public:
+        TestObserver() {}
+        virtual void call(uint8_t) const {}
+        virtual void call(std::string) const {}
+        virtual ~TestObserver() {}
+    };
+
+    extern TestObserver* obs;
+
+    inline void register_observer(TestObserver& a) {
+        obs = &a;
+    }
+    inline void do_a_thing() {
+        return obs->call(8);
+    }
+    "};
+    run_test_ex(
+        "TestObserver* obs;",
+        hdr,
+        quote! {
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::default()
+            );
+            ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
+            ffi::do_a_thing();
+        },
+        quote! {
+            generate!("register_observer")
+            generate!("do_a_thing")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::prelude::*;
+            #[subclass]
+            #[derive(Default)]
+            pub struct MyTestObserver;
+            impl ffi::TestObserver_methods for MyTestObserver {
+                fn call(&self, a: u8) {
+                    self.peer().call_super(a)
+                }
+                fn call1(&self, a: cxx::UniquePtr<cxx::CxxString>) {
+                    self.peer().call1_super(a)
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_overrides() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    #include <string>
+
+    class TestObserver {
+    public:
+        TestObserver() {}
+        virtual void call(uint8_t) const = 0;
+        virtual void call(std::string) const = 0;
+        virtual ~TestObserver() {}
+    };
+
+    extern TestObserver* obs;
+
+    inline void register_observer(TestObserver& a) {
+        obs = &a;
+    }
+    inline void do_a_thing() {
+        return obs->call(8);
+    }
+    "};
+    run_test_ex(
+        "TestObserver* obs;",
+        hdr,
+        quote! {
+            let obs = MyTestObserver::new_rust_owned(
+                MyTestObserver::default()
+            );
+            ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
+            ffi::do_a_thing();
+        },
+        quote! {
+            generate!("register_observer")
+            generate!("do_a_thing")
+            subclass!("TestObserver",MyTestObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::prelude::*;
+            #[subclass]
+            #[derive(Default)]
+            pub struct MyTestObserver;
+            impl ffi::TestObserver_methods for MyTestObserver {
+                fn call(&self, _a: u8) {
+                }
+                fn call1(&self, _a: cxx::UniquePtr<cxx::CxxString>) {
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_pv_subclass_namespaced_superclass() {
+    let hdr = indoc! {"
+    #include <cstdint>
+
+    namespace a {
+    class Observer {
+    public:
+        Observer() {}
+        virtual uint32_t foo() const = 0;
+        virtual ~Observer() {}
+    };
+    }
+    inline void take_observer(const a::Observer&) {}
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {
+            let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
+            ffi::take_observer(o.borrow().as_ref());
+        },
+        quote! {
+            generate!("take_observer")
+            subclass!("a::Observer",MyObserver)
+        },
+        None,
+        None,
+        Some(quote! {
+            use autocxx::subclass::CppSubclass;
+            #[autocxx::subclass::subclass]
+            pub struct MyObserver {
+                a: u32
+            }
+            impl ffi::a::Observer_methods for MyObserver {
+                fn foo(&self) -> u32 {
+                    4
+                }
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_no_constructor_make_unique() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    struct A {
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {
+        ffi::A::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_constructor_moveit() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut stack_obj = ffi::A::new();
+        }
+        stack_obj.as_mut().set(42);
+        assert_eq!(stack_obj.get(), 42);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_move_out_of_uniqueptr() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        std::string so_we_are_non_trivial;
+    };
+    inline A get_a() {
+        A a;
+        return a;
+    }
+    "};
+    let rs = quote! {
+        let a = ffi::get_a().within_unique_ptr();
+        moveit! {
+            let _stack_obj = autocxx::moveit::new::mov(a);
+        }
+    };
+    run_test("", hdr, rs, &["A", "get_a"], &[]);
+}
+
+#[test]
+fn test_implicit_constructor_with_typedef_field() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct B {
+        uint32_t b;
+    };
+    typedef struct B C;
+    struct A {
+        B field;
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut stack_obj = ffi::A::new();
+        }
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_implicit_constructor_with_array_field() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        uint32_t a[3];
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut _stack_obj = ffi::A::new();
+        }
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_implicit_constructor_moveit() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut stack_obj = ffi::A::new();
+        }
+        stack_obj.as_mut().set(42);
+        assert_eq!(stack_obj.get(), 42);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_pass_by_value_moveit() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        void set(uint32_t val) { a = val; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    inline void take_a(A) {}
+    struct B {
+        B() {}
+        B(const B&) {}
+        B(B&&) {}
+        std::string so_we_are_non_trivial;
+    };
+    inline void take_b(B) {}
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut stack_obj = ffi::A::new();
+        }
+        stack_obj.as_mut().set(42);
+        ffi::take_a(&*stack_obj);
+        ffi::take_a(as_copy(stack_obj.as_ref()));
+        ffi::take_a(as_copy(stack_obj.as_ref()));
+        // A has no move constructor so we can't consume it.
+
+        let heap_obj = ffi::A::new().within_unique_ptr();
+        ffi::take_a(heap_obj.as_ref().unwrap());
+        ffi::take_a(&heap_obj);
+        ffi::take_a(autocxx::as_copy(heap_obj.as_ref().unwrap()));
+        ffi::take_a(heap_obj); // consume
+
+        let heap_obj2 = ffi::A::new().within_box();
+        ffi::take_a(heap_obj2.as_ref().get_ref());
+        ffi::take_a(&heap_obj2);
+        ffi::take_a(autocxx::as_copy(heap_obj2.as_ref().get_ref()));
+        ffi::take_a(heap_obj2); // consume
+
+        moveit! {
+            let mut stack_obj = ffi::B::new();
+        }
+        ffi::take_b(&*stack_obj);
+        ffi::take_b(as_copy(stack_obj.as_ref()));
+        ffi::take_b(as_copy(stack_obj.as_ref()));
+        ffi::take_b(as_mov(stack_obj)); // due to move constructor
+
+        // Test direct-from-New-to-param.
+        ffi::take_b(as_new(ffi::B::new()));
+    };
+    run_test("", hdr, rs, &["A", "take_a", "B", "take_b"], &[]);
+}
+
+#[test]
+fn test_nonconst_reference_parameter() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+
+    // Force generating a wrapper for the second `take_a`.
+    struct NOP { void take_a() {}; };
+
+    struct A {
+        std::string so_we_are_non_trivial;
+    };
+    inline void take_a(A&) {}
+    "};
+    let rs = quote! {
+        let mut heap_obj = ffi::A::new().within_unique_ptr();
+        ffi::take_a(heap_obj.pin_mut());
+    };
+    run_test("", hdr, rs, &["NOP", "A", "take_a"], &[]);
+}
+
+#[test]
+fn test_nonconst_reference_method_parameter() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+
+    // Force generating a wrapper for the second `take_a`.
+    struct NOP { void take_a() {}; };
+
+    struct A {
+        std::string so_we_are_non_trivial;
+    };
+    struct B {
+        inline void take_a(A&) const {}
+    };
+    "};
+    let rs = quote! {
+        let mut a = ffi::A::new().within_unique_ptr();
+        let b = ffi::B::new().within_unique_ptr();
+        b.take_a(a.pin_mut());
+    };
+    run_test("", hdr, rs, &["NOP", "A", "B"], &[]);
+}
+
+fn destruction_test(ident: proc_macro2::Ident, extra_bit: Option<TokenStream>) {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    extern bool gConstructed;
+    struct A {
+        A() { gConstructed = true; }
+        virtual ~A() { gConstructed = false; }
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    inline bool is_constructed() { return gConstructed; }
+    struct B: public A {
+        uint32_t b;
+    };
+    "};
+    let cpp = indoc! {"
+        bool gConstructed = false;
+    "};
+    let rs = quote! {
+        assert!(!ffi::is_constructed());
+        {
+            moveit! {
+                let mut _stack_obj = ffi::#ident::new();
+            }
+            assert!(ffi::is_constructed());
+            #extra_bit
+        }
+        assert!(!ffi::is_constructed());
+    };
+    run_test(cpp, hdr, rs, &[&ident.to_string(), "is_constructed"], &[]);
+}
+
+#[test]
+fn test_destructor_moveit() {
+    destruction_test(
+        parse_quote! { A },
+        Some(quote! {
+            _stack_obj.as_mut().set(42);
+            assert_eq!(_stack_obj.get(), 42);
+        }),
+    );
+}
+
+#[test]
+fn test_destructor_derived_moveit() {
+    destruction_test(parse_quote! { B }, None);
+}
+
+#[test]
+fn test_copy_and_move_constructor_moveit() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        A(const A& other) : a(other.a+1) {}
+        A(A&& other) : a(other.a+2) { other.a = 666; }
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        moveit! {
+            let mut stack_obj = ffi::A::new();
+        }
+        stack_obj.as_mut().set(42);
+        moveit! {
+            let stack_obj2 = autocxx::moveit::new::copy(stack_obj.as_ref());
+        }
+        assert_eq!(stack_obj2.get(), 43);
+        assert_eq!(stack_obj.get(), 42);
+        moveit! {
+            let stack_obj3 = autocxx::moveit::new::mov(stack_obj);
+        }
+        assert_eq!(stack_obj3.get(), 44);
+        // Following line prevented by moveit, even though it would
+        // be possible in C++.
+        // assert_eq!(stack_obj.get(), 666);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+// This test fails on Windows gnu but not on Windows msvc
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[test]
+fn test_uniqueptr_moveit() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        use autocxx::moveit::EmplaceUnpinned;
+        let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
+        up_obj.as_mut().unwrap().set(42);
+        assert_eq!(up_obj.get(), 42);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+// This test fails on Windows gnu but not on Windows msvc
+#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
+#[test]
+fn test_various_emplacement() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {
+        use autocxx::moveit::EmplaceUnpinned;
+        use autocxx::moveit::Emplace;
+        let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
+        up_obj.pin_mut().set(666);
+        // Can't current move out of a UniquePtr
+        let mut box_obj = Box::emplace(ffi::A::new());
+        box_obj.as_mut().set(667);
+        let box_obj2 = Box::emplace(autocxx::moveit::new::mov(box_obj));
+        moveit! { let back_on_stack = autocxx::moveit::new::mov(box_obj2); }
+        assert_eq!(back_on_stack.get(), 667);
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_emplace_uses_overridden_new_and_delete() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {}
+        void* operator new(size_t count);
+        void operator delete(void* ptr) noexcept;
+        void* operator new(size_t count, void* ptr);
+        std::string so_we_are_non_trivial;
+    };
+    void reset_flags();
+    bool was_new_called();
+    bool was_delete_called();
+    "};
+    let cxx = indoc! {"
+        bool new_called;
+        bool delete_called;
+        void reset_flags() {
+            new_called = false;
+            delete_called = false;
+        }
+        void* A::operator new(size_t count) {
+            new_called = true;
+            return ::operator new(count);
+        }
+        void* A::operator new(size_t count, void* ptr) {
+            return ::operator new(count, ptr);
+        }
+        void A::operator delete(void* ptr) noexcept {
+            delete_called = true;
+            ::operator delete(ptr);
+        }
+        bool was_new_called() {
+            return new_called;
+        }
+        bool was_delete_called() {
+            return delete_called;
+        }
+    "};
+    let rs = quote! {
+        ffi::reset_flags();
+        {
+            let _ = ffi::A::new().within_unique_ptr();
+            assert!(ffi::was_new_called());
+        }
+        assert!(ffi::was_delete_called());
+        ffi::reset_flags();
+        {
+            use autocxx::moveit::EmplaceUnpinned;
+            let _ = cxx::UniquePtr::emplace(ffi::A::new());
+        }
+        assert!(ffi::was_delete_called());
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &["A", "reset_flags", "was_new_called", "was_delete_called"],
+        &[],
+    );
+}
+
+#[test]
+fn test_pass_by_reference_to_value_param() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() : count(0) {}
+        std::string so_we_are_non_trivial;
+        uint32_t count;
+    };
+    void take_a(A a) {
+        a.count++;
+    }
+    uint32_t report_on_a(const A& a) {
+        return a.count;
+    }
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        ffi::take_a(a.as_ref().unwrap());
+        ffi::take_a(&a); // syntactic sugar
+        assert_eq!(ffi::report_on_a(&a), 0); // should have acted upon copies
+    };
+    run_test("", hdr, rs, &["A", "take_a", "report_on_a"], &[]);
+}
+
+#[test]
+fn test_explicit_everything() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    struct A {
+        A() {} // default constructor
+        A(A&&) {} // move constructor
+        A(const A&) {} // copy constructor
+        A& operator=(const A&) { return *this; } // copy assignment operator
+        A& operator=(A&&) { return *this; } // move assignment operator
+        ~A() {} // destructor
+        void set(uint32_t val) { a = val; }
+        uint32_t get() const { return a; }
+        uint32_t a;
+        std::string so_we_are_non_trivial;
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_generate_ns() {
+    let hdr = indoc! {"
+    namespace A {
+        inline void foo() {}
+        inline void bar() {}
+    }
+    namespace B {
+        inline void baz() {}
+    }
+    "};
+    let rs = quote! {
+        ffi::A::foo();
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! {
+            generate_ns!("A")
+            safety!(unsafe_ffi)
+        },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_no_constructor_make_unique_ns() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    namespace B {
+    struct A {
+        uint32_t a;
+    };
+    }
+    "};
+    let rs = quote! {
+        ffi::B::A::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &["B::A"], &[]);
+}
+
+#[test]
+fn test_no_constructor_pod_make_unique() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    struct A {
+        uint32_t a;
+    };
+    "};
+    let rs = quote! {
+        ffi::A::new().within_unique_ptr();
+    };
+    run_test("", hdr, rs, &[], &["A"]);
+}
+
+#[test]
+fn test_no_constructor_pv() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    class A {
+    public:
+        virtual ~A() {}
+        virtual void foo() = 0;
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_suppress_system_includes() {
+    let hdr = indoc! {"
+    #include <stdint.h>
+    #include <string>
+    inline void a() {};
+    "};
+    let rs = quote! {};
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate("a")},
+        Some(Box::new(SetSuppressSystemHeaders)),
+        Some(Box::new(NoSystemHeadersChecker)),
+        None,
+    );
+}
+
+#[test]
+fn test_no_rvo_move() {
+    let hdr = indoc! {"
+    #include <memory>
+    class A {
+    public:
+        static std::unique_ptr<A> create() { return std::make_unique<A>(); }
+    };
+    "};
+    let rs = quote! {
+        ffi::A::create();
+    };
+    run_test_ex(
+        "",
+        hdr,
+        rs,
+        quote! { generate!("A") },
+        None,
+        Some(Box::new(CppMatcher::new(
+            &["return A::create();"],
+            &["return std::move(A::create());"],
+        ))),
+        None,
+    );
+}
+
+#[test]
+fn test_abstract_up() {
+    let hdr = indoc! {"
+    #include <memory>
+    class A {
+    public:
+        virtual void foo() const = 0;
+        virtual ~A() {}
+    };
+    class B : public A {
+    public:
+        void foo() const {}
+    };
+    inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
+    "};
+    let rs = quote! {
+        let a = ffi::get_a();
+        a.foo();
+    };
+    run_test("", hdr, rs, &["A", "get_a"], &[]);
+}
+
+#[test]
+fn test_abstract_private() {
+    let hdr = indoc! {"
+    #include <memory>
+    class A {
+        virtual void foo() const = 0;
+    public:
+        virtual ~A() {}
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_abstract_issue_979() {
+    let hdr = indoc! {"
+    class Test {
+        virtual ~Test() {}
+        virtual void TestBody() = 0;
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["Test"], &[]);
+}
+
+#[test]
+fn test_class_having_protected_method() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    class A {
+    protected:
+        inline uint32_t protected_method() { return 0; }
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["A"]);
+}
+
+#[test]
+fn test_protected_inner_class() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    inline uint32_t DoMath(uint32_t a)  {
+        return a * 3;
+    }
+
+    class A {
+    protected:
+        inline uint32_t protected_method() { return 0; }
+
+        struct B {
+            int x;
+        };
+
+        inline B protected_method_2() {
+            return { 0 };
+        }
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_private_inner_class() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    inline uint32_t DoMath(uint32_t a)  {
+        return a * 3;
+    }
+
+    class A {
+    protected:
+        inline uint32_t protected_method() { return 0; }
+
+    private:
+        struct B {
+            int x;
+        };
+
+        inline B private_method_2() {
+            return { 0 };
+        }
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_class_having_private_method() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    class A {
+    private:
+        inline uint32_t private_method() { return 0; }
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["A"]);
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/787
+fn test_chrono_problem() {
+    let hdr = indoc! {"
+    #include <chrono>
+    struct Clock {
+      typedef std::chrono::nanoseconds duration;
+    };
+    struct Class {
+      int a() { return 42; }
+      std::chrono::time_point<Clock> b();
+    };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &[], &["Class"]);
+}
+
+fn size_and_alignment_test(pod: bool) {
+    static TYPES: [(&str, &str); 6] = [
+        ("A", "struct A { uint8_t a; };"),
+        ("B", "struct B { uint32_t a; };"),
+        ("C", "struct C { uint64_t a; };"),
+        ("D", "enum D { Z, X };"),
+        ("E", "struct E { uint8_t a; uint32_t b; };"),
+        ("F", "struct F { uint32_t a; uint8_t b; };"),
+    ];
+    let type_definitions = TYPES.iter().map(|(_, def)| *def).join("\n");
+    let function_definitions = TYPES.iter().map(|(name, _)| format!("inline size_t get_sizeof_{}() {{ return sizeof({}); }}\ninline size_t get_alignof_{}() {{ return alignof({}); }}\n",
+    name, name, name, name)).join("\n");
+    let hdr = format!(
+        indoc! {"
+        #include <cstdint>
+        #include <cstddef>
+        {}
+        {}
+    "},
+        type_definitions, function_definitions
+    );
+    #[allow(clippy::unnecessary_to_owned)] // wrongly triggers on into_iter() below
+    let allowlist_fns: Vec<String> = TYPES
+        .iter()
+        .flat_map(|(name, _)| {
+            [
+                format!("get_sizeof_{}", name),
+                format!("get_alignof_{}", name),
+            ]
+            .to_vec()
+            .into_iter()
+        })
+        .collect_vec();
+    let allowlist_types: Vec<String> = TYPES.iter().map(|(name, _)| name.to_string()).collect_vec();
+    let allowlist_both = allowlist_types
+        .iter()
+        .cloned()
+        .chain(allowlist_fns.iter().cloned())
+        .collect_vec();
+    let allowlist_types: Vec<&str> = allowlist_types.iter().map(AsRef::as_ref).collect_vec();
+    let allowlist_fns: Vec<&str> = allowlist_fns.iter().map(AsRef::as_ref).collect_vec();
+    let allowlist_both: Vec<&str> = allowlist_both.iter().map(AsRef::as_ref).collect_vec();
+    let rs = TYPES.iter().fold(quote! {}, |mut accumulator, (name, _)| {
+        let get_align_symbol =
+            proc_macro2::Ident::new(&format!("get_alignof_{}", name), Span::call_site());
+        let get_size_symbol =
+            proc_macro2::Ident::new(&format!("get_sizeof_{}", name), Span::call_site());
+        let type_symbol = proc_macro2::Ident::new(name, Span::call_site());
+        accumulator.extend(quote! {
+            let c_size = ffi::#get_size_symbol();
+            let c_align = ffi::#get_align_symbol();
+            assert_eq!(std::mem::size_of::<ffi::#type_symbol>(), c_size);
+            assert_eq!(std::mem::align_of::<ffi::#type_symbol>(), c_align);
+        });
+        accumulator
+    });
+    if pod {
+        run_test("", &hdr, rs, &allowlist_fns, &allowlist_types);
+    } else {
+        run_test("", &hdr, rs, &allowlist_both, &[]);
+    }
+}
+
+#[test]
+fn test_sizes_and_alignment_nonpod() {
+    size_and_alignment_test(false)
+}
+
+#[test]
+fn test_sizes_and_alignment_pod() {
+    size_and_alignment_test(true)
+}
+
+#[test]
+fn test_nested_class_methods() {
+    let hdr = indoc! {"
+    #include <cstdint>
+    class A {
+    public:
+        virtual ~A() {}
+        struct B {
+            virtual void b() const {}
+        };
+        virtual void a() const {}
+        struct C {
+            virtual void b() const {}
+        };
+        virtual void c() const {}
+        struct D {
+            virtual void b() const {}
+        };
+    };
+    "};
+    let rs = quote! {
+        let a = ffi::A::new().within_unique_ptr();
+        a.a();
+        a.c();
+    };
+    run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_call_superclass() {
+    let hdr = indoc! {"
+    #include <memory>
+    class A {
+    public:
+        virtual void foo() const {};
+        virtual ~A() {}
+    };
+    class B : public A {
+    public:
+        void bar() const {}
+    };
+    inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
+    "};
+    let rs = quote! {
+        let b = ffi::get_b();
+        b.as_ref().unwrap().as_ref().foo();
+    };
+    run_test("", hdr, rs, &["A", "B", "get_b"], &[]);
+}
+
+#[test]
+fn test_pass_superclass() {
+    let hdr = indoc! {"
+    #include <memory>
+    class A {
+    public:
+        virtual void foo() const {};
+        virtual ~A() {}
+    };
+    class B : public A {
+    public:
+        void bar() const {}
+    };
+    inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
+    inline void take_a(const A&) {}
+    "};
+    let rs = quote! {
+        let b = ffi::get_b();
+        ffi::take_a(b.as_ref().unwrap().as_ref());
+    };
+    run_test("", hdr, rs, &["A", "B", "get_b", "take_a"], &[]);
+}
+
+#[test]
+fn test_issue486_multi_types() {
+    let hdr = indoc! {"
+        namespace a {
+            namespace spanner {
+                struct Key {};
+            }
+        } // namespace a
+        namespace b {
+            namespace spanner {
+                typedef int Key;
+            }
+        } // namespace b
+        namespace c {
+            namespace spanner {
+                enum Key { A, B };
+            }
+        } // namespace c
+        namespace spanner {
+            class Key {
+                public:
+                    bool a(a::spanner::Key &);
+                    bool b(b::spanner::Key &);
+                    bool c(c::spanner::Key &);
+            };
+        } // namespace spanner
+    "};
+    let rs = quote! {};
+    run_test(
+        "",
+        hdr,
+        rs,
+        &["spanner::Key", "a::spanner::Key", "b::spanner::Key"],
+        &[],
+    );
+}
+
+#[test]
+/// Tests types with various forms of copy, move, and default constructors. Calls the things which
+/// should be generated, and will produce C++ compile failures if other wrappers are generated.
+///
+/// Specifically, we can have the cross product of any of these:
+///   * Explicitly deleted
+///   * Implicitly defaulted
+///   * User declared
+///   * Explicitly defaulted
+///     Not handled yet: https://github.com/google/autocxx/issues/815.
+///     Once this is handled, add equivalents of all the implicitly defaulted cases, at all
+///     visibility levels.
+/// applied to each of these:
+///   * Default constructor
+///   * Copy constructor
+///   * Move constructor
+/// in any of these:
+///   * The class itself
+///   * A base class
+///   * A field of the class
+///   * A field of a base class
+/// with any of these access modifiers:
+///   * private (impossible for implicitly defaulted)
+///   * protected (impossible for implicitly defaulted)
+///   * public
+///
+/// Various combinations of these lead to the default versions being deleted. The move and copy
+/// ones also interact with each other in various ways.
+///
+/// TODO: Remove all the `int x` members after https://github.com/google/autocxx/issues/832 is
+/// fixed.
+fn test_implicit_constructor_rules() {
+    let cxx = "";
+    let hdr = indoc! {"
+        struct AllImplicitlyDefaulted {
+            void a() const {}
+        };
+
+        struct PublicDeleted {
+            PublicDeleted() = delete;
+            PublicDeleted(const PublicDeleted&) = delete;
+            PublicDeleted(PublicDeleted&&) = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDeletedDefault {
+            PublicDeletedDefault() = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDeletedCopy {
+            PublicDeletedCopy() = default;
+            PublicDeletedCopy(const PublicDeletedCopy&) = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDeletedCopyNoDefault {
+            PublicDeletedCopyNoDefault(const PublicDeletedCopyNoDefault&) = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicMoveDeletedCopy {
+            PublicMoveDeletedCopy() = default;
+            PublicMoveDeletedCopy(const PublicMoveDeletedCopy&) = delete;
+            PublicMoveDeletedCopy(PublicMoveDeletedCopy&&) = default;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDeletedMove {
+            PublicDeletedMove() = default;
+            PublicDeletedMove(PublicDeletedMove&&) = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDeletedDestructor {
+            PublicDeletedDestructor() = default;
+            ~PublicDeletedDestructor() = delete;
+
+            void a() const {}
+
+            int x;
+        };
+        struct PublicDestructor {
+            PublicDestructor() = default;
+            ~PublicDestructor() = default;
+
+            void a() const {}
+
+            int x;
+        };
+
+        struct ProtectedDeleted {
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedDeleted() = delete;
+            ProtectedDeleted(const ProtectedDeleted&) = delete;
+            ProtectedDeleted(ProtectedDeleted&&) = delete;
+        };
+        struct ProtectedDeletedDefault {
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedDeletedDefault() = delete;
+        };
+        struct ProtectedDeletedCopy {
+            ProtectedDeletedCopy() = default;
+
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedDeletedCopy(const ProtectedDeletedCopy&) = delete;
+        };
+        struct ProtectedDeletedCopyNoDefault {
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedDeletedCopyNoDefault(const ProtectedDeletedCopyNoDefault&) = delete;
+        };
+        struct ProtectedMoveDeletedCopy {
+            ProtectedMoveDeletedCopy() = default;
+
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedMoveDeletedCopy(const ProtectedMoveDeletedCopy&) = delete;
+            ProtectedMoveDeletedCopy(ProtectedMoveDeletedCopy&&) = default;
+        };
+        struct ProtectedDeletedMove {
+            ProtectedDeletedMove() = default;
+
+            void a() const {}
+
+            int x;
+
+          protected:
+            ProtectedDeletedMove(ProtectedDeletedMove&&) = delete;
+        };
+        struct ProtectedDeletedDestructor {
+            ProtectedDeletedDestructor() = default;
+
+            void a() const {}
+
+            int x;
+
+          protected:
+            ~ProtectedDeletedDestructor() = delete;
+        };
+        struct ProtectedDestructor {
+            ProtectedDestructor() = default;
+
+            void a() const {}
+
+            int x;
+
+          protected:
+            ~ProtectedDestructor() = default;
+        };
+
+        struct PrivateDeleted {
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateDeleted() = delete;
+            PrivateDeleted(const PrivateDeleted&) = delete;
+            PrivateDeleted(PrivateDeleted&&) = delete;
+        };
+        struct PrivateDeletedDefault {
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateDeletedDefault() = delete;
+        };
+        struct PrivateDeletedCopy {
+            PrivateDeletedCopy() = default;
+
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateDeletedCopy(const PrivateDeletedCopy&) = delete;
+        };
+        struct PrivateDeletedCopyNoDefault {
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateDeletedCopyNoDefault(const PrivateDeletedCopyNoDefault&) = delete;
+        };
+        struct PrivateMoveDeletedCopy {
+            PrivateMoveDeletedCopy() = default;
+
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateMoveDeletedCopy(const PrivateMoveDeletedCopy&) = delete;
+            PrivateMoveDeletedCopy(PrivateMoveDeletedCopy&&) = default;
+        };
+        struct PrivateDeletedMove {
+            PrivateDeletedMove() = default;
+
+            void a() const {}
+
+            int x;
+
+          private:
+            PrivateDeletedMove(PrivateDeletedMove&&) = delete;
+        };
+        struct PrivateDeletedDestructor {
+            PrivateDeletedDestructor() = default;
+
+            void a() const {}
+
+            int x;
+
+          private:
+            ~PrivateDeletedDestructor() = delete;
+        };
+        struct PrivateDestructor {
+            PrivateDestructor() = default;
+
+            void a() const {}
+
+            int x;
+
+          private:
+            ~PrivateDestructor() = default;
+        };
+
+        struct NonConstCopy {
+            NonConstCopy() = default;
+
+            NonConstCopy(NonConstCopy&) {}
+            NonConstCopy(NonConstCopy&&) = default;
+
+            void a() const {}
+        };
+        struct TwoCopy {
+            TwoCopy() = default;
+
+            TwoCopy(TwoCopy&) {}
+            TwoCopy(const TwoCopy&) {}
+            TwoCopy(TwoCopy&&) = default;
+
+            void a() const {}
+        };
+
+        struct MemberPointerDeleted {
+            PublicDeleted *x;
+
+            void a() const {}
+        };
+
+        struct MemberConstPointerDeleted {
+            PublicDeleted *const x;
+
+            void a() const {}
+        };
+
+        struct MemberConst {
+            const int x;
+
+            void a() const {}
+        };
+
+        struct MemberReferenceDeleted {
+            PublicDeleted &x;
+
+            void a() const {}
+        };
+
+        struct MemberConstReferenceDeleted {
+            const PublicDeleted &x;
+
+            void a() const {}
+        };
+
+        struct MemberReference {
+            int &x;
+
+            void a() const {}
+        };
+
+        struct MemberConstReference {
+            const int &x;
+
+            void a() const {}
+        };
+
+        struct MemberRvalueReferenceDeleted {
+            PublicDeleted &&x;
+
+            void a() const {}
+        };
+
+        struct MemberRvalueReference {
+            int &&x;
+
+            void a() const {}
+        };
+
+        struct BasePublicDeleted : public PublicDeleted {};
+        struct BasePublicDeletedDefault : public PublicDeletedDefault {};
+        struct BasePublicDeletedCopy : public PublicDeletedCopy {};
+        struct BasePublicDeletedCopyNoDefault : public PublicDeletedCopyNoDefault { };
+        struct BasePublicMoveDeletedCopy : public PublicMoveDeletedCopy {};
+        struct BasePublicDeletedMove : public PublicDeletedMove {};
+        struct BasePublicDeletedDestructor : public PublicDeletedDestructor {};
+        struct BasePublicDestructor : public PublicDestructor {};
+
+        struct MemberPublicDeleted {
+            void a() const {}
+
+            PublicDeleted member;
+        };
+        struct MemberPublicDeletedDefault {
+            void a() const {}
+
+            PublicDeletedDefault member;
+        };
+        struct MemberPublicDeletedCopy {
+            void a() const {}
+
+            PublicDeletedCopy member;
+        };
+        struct MemberPublicDeletedCopyNoDefault {
+            void a() const {}
+
+            PublicDeletedCopyNoDefault member;
+        };
+        struct MemberPublicMoveDeletedCopy {
+            void a() const {}
+
+            PublicMoveDeletedCopy member;
+        };
+        struct MemberPublicDeletedMove {
+            void a() const {}
+
+            PublicDeletedMove member;
+        };
+        struct MemberPublicDeletedDestructor {
+            void a() const {}
+
+            PublicDeletedDestructor member;
+        };
+        struct MemberPublicDestructor {
+            void a() const {}
+
+            PublicDestructor member;
+        };
+
+        struct BaseMemberPublicDeleted : public MemberPublicDeleted {};
+        struct BaseMemberPublicDeletedDefault : public MemberPublicDeletedDefault {};
+        struct BaseMemberPublicDeletedCopy : public MemberPublicDeletedCopy {};
+        struct BaseMemberPublicDeletedCopyNoDefault : public MemberPublicDeletedCopyNoDefault {};
+        struct BaseMemberPublicMoveDeletedCopy : public MemberPublicMoveDeletedCopy {};
+        struct BaseMemberPublicDeletedMove : public MemberPublicDeletedMove {};
+        struct BaseMemberPublicDeletedDestructor : public MemberPublicDeletedDestructor {};
+        struct BaseMemberPublicDestructor : public MemberPublicDestructor {};
+
+        struct BaseProtectedDeleted : public ProtectedDeleted {};
+        struct BaseProtectedDeletedDefault : public ProtectedDeletedDefault {};
+        struct BaseProtectedDeletedCopy : public ProtectedDeletedCopy {};
+        struct BaseProtectedDeletedCopyNoDefault : public ProtectedDeletedCopyNoDefault {};
+        struct BaseProtectedMoveDeletedCopy : public ProtectedMoveDeletedCopy {};
+        struct BaseProtectedDeletedMove : public ProtectedDeletedMove {};
+        struct BaseProtectedDeletedDestructor : public ProtectedDeletedDestructor {};
+        struct BaseProtectedDestructor : public ProtectedDestructor {};
+
+        struct MemberProtectedDeleted {
+            void a() const {}
+
+            ProtectedDeleted member;
+        };
+        struct MemberProtectedDeletedDefault {
+            void a() const {}
+
+            ProtectedDeletedDefault member;
+        };
+        struct MemberProtectedDeletedCopy {
+            void a() const {}
+
+            ProtectedDeletedCopy member;
+        };
+        struct MemberProtectedDeletedCopyNoDefault {
+            void a() const {}
+
+            ProtectedDeletedCopyNoDefault member;
+        };
+        struct MemberProtectedMoveDeletedCopy {
+            void a() const {}
+
+            ProtectedMoveDeletedCopy member;
+        };
+        struct MemberProtectedDeletedMove {
+            void a() const {}
+
+            ProtectedDeletedMove member;
+        };
+        struct MemberProtectedDeletedDestructor {
+            void a() const {}
+
+            ProtectedDeletedDestructor member;
+        };
+        struct MemberProtectedDestructor {
+            void a() const {}
+
+            ProtectedDestructor member;
+        };
+
+        struct BaseMemberProtectedDeleted : public MemberProtectedDeleted {};
+        struct BaseMemberProtectedDeletedDefault : public MemberProtectedDeletedDefault {};
+        struct BaseMemberProtectedDeletedCopy : public MemberProtectedDeletedCopy {};
+        struct BaseMemberProtectedDeletedCopyNoDefault : public MemberProtectedDeletedCopyNoDefault {};
+        struct BaseMemberProtectedMoveDeletedCopy : public MemberProtectedMoveDeletedCopy {};
+        struct BaseMemberProtectedDeletedMove : public MemberProtectedDeletedMove {};
+        struct BaseMemberProtectedDeletedDestructor : public MemberProtectedDeletedDestructor {};
+        struct BaseMemberProtectedDestructor : public MemberProtectedDestructor {};
+
+        struct BasePrivateDeleted : public PrivateDeleted {};
+        struct BasePrivateDeletedDefault : public PrivateDeletedDefault {};
+        struct BasePrivateDeletedCopy : public PrivateDeletedCopy {};
+        struct BasePrivateDeletedCopyNoDefault : public PrivateDeletedCopyNoDefault {};
+        struct BasePrivateMoveDeletedCopy : public PrivateMoveDeletedCopy {};
+        struct BasePrivateDeletedMove : public PrivateDeletedMove {};
+        struct BasePrivateDeletedDestructor : public PrivateDeletedDestructor {};
+        struct BasePrivateDestructor : public PrivateDestructor {};
+
+        struct MemberPrivateDeleted {
+            void a() const {}
+
+            PrivateDeleted member;
+        };
+        struct MemberPrivateDeletedDefault {
+            void a() const {}
+
+            PrivateDeletedDefault member;
+        };
+        struct MemberPrivateDeletedCopy {
+            void a() const {}
+
+            PrivateDeletedCopy member;
+        };
+        struct MemberPrivateDeletedCopyNoDefault {
+            void a() const {}
+
+            PrivateDeletedCopyNoDefault member;
+        };
+        struct MemberPrivateMoveDeletedCopy {
+            void a() const {}
+
+            PrivateMoveDeletedCopy member;
+        };
+        struct MemberPrivateDeletedMove {
+            void a() const {}
+
+            PrivateDeletedMove member;
+        };
+        struct MemberPrivateDeletedDestructor {
+            void a() const {}
+
+            PrivateDeletedDestructor member;
+        };
+        struct MemberPrivateDestructor {
+            void a() const {}
+
+            PrivateDestructor member;
+        };
+
+        struct BaseMemberPrivateDeleted : public MemberPrivateDeleted {};
+        struct BaseMemberPrivateDeletedDefault : public MemberPrivateDeletedDefault {};
+        struct BaseMemberPrivateDeletedCopy : public MemberPrivateDeletedCopy {};
+        struct BaseMemberPrivateDeletedCopyNoDefault : public MemberPrivateDeletedCopyNoDefault {};
+        struct BaseMemberPrivateMoveDeletedCopy : public MemberPrivateMoveDeletedCopy {};
+        struct BaseMemberPrivateDeletedMove : public MemberPrivateDeletedMove {};
+        struct BaseMemberPrivateDeletedDestructor : public MemberPrivateDeletedDestructor {};
+        struct BaseMemberPrivateDestructor : public MemberPrivateDestructor {};
+    "};
+    let rs = quote! {
+        // Some macros to test various operations on our types. Note that some of them define
+        // functions which take arguments that the APIs defined in this test have no way to
+        // produce, because we have C++ types which can't be constructed (for example). In a real
+        // program, there might be other C++ APIs which can instantiate these types.
+
+        // TODO: https://github.com/google/autocxx/issues/829: Should this be merged with
+        // `test_make_unique`? Currently types where the Rust wrappers permit this but not that
+        // aren't running C++ destructors.
+        macro_rules! test_constructible {
+            [$t:ty] => {
+                moveit! {
+                    let _moveit_t = <$t>::new();
+                }
+            }
+        }
+        macro_rules! test_make_unique {
+            [$t:ty] => {
+                let _unique_t = <$t>::new().within_unique_ptr();
+            }
+        }
+        macro_rules! test_copyable {
+            [$t:ty] => {
+                {
+                    fn test_copyable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
+                        moveit! {
+                            let moveit_t = moveit_t;
+                            let _copied_t = autocxx::moveit::new::copy(moveit_t);
+                        }
+                    }
+                }
+            }
+        }
+        macro_rules! test_movable {
+            [$t:ty] => {
+                {
+                    fn test_movable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
+                        moveit! {
+                            let moveit_t = moveit_t;
+                            let _moved_t = autocxx::moveit::new::mov(moveit_t);
+                        }
+                    }
+                }
+            }
+        }
+        macro_rules! test_call_a {
+            [$t:ty] => {
+                {
+                    fn test_call_a(t: &$t) {
+                        t.a();
+                    }
+                }
+            }
+        }
+        macro_rules! test_call_a_as {
+            [$t:ty, $parent:ty] => {
+                {
+                    fn test_call_a(t: &$t) {
+                        let t: &$parent = t.as_ref();
+                        t.a();
+                    }
+                }
+            }
+        }
+
+        test_constructible![ffi::AllImplicitlyDefaulted];
+        test_make_unique![ffi::AllImplicitlyDefaulted];
+        test_copyable![ffi::AllImplicitlyDefaulted];
+        test_movable![ffi::AllImplicitlyDefaulted];
+        test_call_a![ffi::AllImplicitlyDefaulted];
+
+        test_call_a![ffi::PublicDeleted];
+
+        test_copyable![ffi::PublicDeletedDefault];
+        test_movable![ffi::PublicDeletedDefault];
+        test_call_a![ffi::PublicDeletedDefault];
+
+        test_constructible![ffi::PublicDeletedCopy];
+        test_make_unique![ffi::PublicDeletedCopy];
+        test_call_a![ffi::PublicDeletedCopy];
+
+        test_call_a![ffi::PublicDeletedCopyNoDefault];
+
+        test_constructible![ffi::PublicMoveDeletedCopy];
+        test_make_unique![ffi::PublicMoveDeletedCopy];
+        test_movable![ffi::PublicMoveDeletedCopy];
+        test_call_a![ffi::PublicMoveDeletedCopy];
+
+        test_constructible![ffi::PublicDeletedMove];
+        test_make_unique![ffi::PublicDeletedMove];
+        test_call_a![ffi::PublicDeletedMove];
+
+        test_constructible![ffi::PublicDeletedDestructor];
+        test_copyable![ffi::PublicDeletedDestructor];
+        test_call_a![ffi::PublicDeletedDestructor];
+
+        test_constructible![ffi::PublicDestructor];
+        test_make_unique![ffi::PublicDestructor];
+        test_copyable![ffi::PublicDestructor];
+        test_call_a![ffi::PublicDestructor];
+
+        test_call_a![ffi::ProtectedDeleted];
+
+        test_copyable![ffi::ProtectedDeletedDefault];
+        test_movable![ffi::ProtectedDeletedDefault];
+        test_call_a![ffi::ProtectedDeletedDefault];
+
+        test_constructible![ffi::ProtectedDeletedCopy];
+        test_make_unique![ffi::ProtectedDeletedCopy];
+        test_call_a![ffi::ProtectedDeletedCopy];
+
+        test_call_a![ffi::ProtectedDeletedCopyNoDefault];
+
+        test_constructible![ffi::ProtectedMoveDeletedCopy];
+        test_make_unique![ffi::ProtectedMoveDeletedCopy];
+        test_call_a![ffi::ProtectedMoveDeletedCopy];
+
+        test_constructible![ffi::ProtectedDeletedMove];
+        test_make_unique![ffi::ProtectedDeletedMove];
+        test_call_a![ffi::ProtectedDeletedMove];
+
+        test_constructible![ffi::ProtectedDeletedDestructor];
+        test_copyable![ffi::ProtectedDeletedDestructor];
+        test_call_a![ffi::ProtectedDeletedDestructor];
+
+        test_constructible![ffi::ProtectedDestructor];
+        test_copyable![ffi::ProtectedDestructor];
+        test_call_a![ffi::ProtectedDestructor];
+
+        test_call_a![ffi::PrivateDeleted];
+
+        test_copyable![ffi::PrivateDeletedDefault];
+        test_movable![ffi::PrivateDeletedDefault];
+        test_call_a![ffi::PrivateDeletedDefault];
+
+        test_constructible![ffi::PrivateDeletedCopy];
+        test_make_unique![ffi::PrivateDeletedCopy];
+        test_call_a![ffi::PrivateDeletedCopy];
+
+        test_call_a![ffi::PrivateDeletedCopyNoDefault];
+
+        test_constructible![ffi::PrivateMoveDeletedCopy];
+        test_make_unique![ffi::PrivateMoveDeletedCopy];
+        test_call_a![ffi::PrivateMoveDeletedCopy];
+
+        test_constructible![ffi::PrivateDeletedMove];
+        test_make_unique![ffi::PrivateDeletedMove];
+        test_call_a![ffi::PrivateDeletedMove];
+
+        test_constructible![ffi::PrivateDeletedDestructor];
+        test_copyable![ffi::PrivateDeletedDestructor];
+        test_call_a![ffi::PrivateDeletedDestructor];
+
+        test_constructible![ffi::PrivateDestructor];
+        test_copyable![ffi::PrivateDestructor];
+        test_call_a![ffi::PrivateDestructor];
+
+        test_constructible![ffi::NonConstCopy];
+        test_make_unique![ffi::NonConstCopy];
+        test_movable![ffi::NonConstCopy];
+        test_call_a![ffi::NonConstCopy];
+
+        test_constructible![ffi::TwoCopy];
+        test_make_unique![ffi::TwoCopy];
+        test_copyable![ffi::TwoCopy];
+        test_movable![ffi::TwoCopy];
+        test_call_a![ffi::TwoCopy];
+
+        // TODO: https://github.com/google/autocxx/issues/865
+        // Treat pointers and references differently so this has a default constructor.
+        //test_constructible![ffi::MemberPointerDeleted];
+        //test_make_unique![ffi::MemberPointerDeleted];
+        test_copyable![ffi::MemberPointerDeleted];
+        test_movable![ffi::MemberPointerDeleted];
+        test_call_a![ffi::MemberPointerDeleted];
+
+        test_copyable![ffi::MemberConstPointerDeleted];
+        test_movable![ffi::MemberConstPointerDeleted];
+        test_call_a![ffi::MemberConstPointerDeleted];
+
+        //test_copyable![ffi::MemberConst];
+        //test_movable![ffi::MemberConst];
+        //test_call_a![ffi::MemberConst];
+
+        test_copyable![ffi::MemberReferenceDeleted];
+        test_movable![ffi::MemberReferenceDeleted];
+        test_call_a![ffi::MemberReferenceDeleted];
+
+        test_copyable![ffi::MemberConstReferenceDeleted];
+        test_movable![ffi::MemberConstReferenceDeleted];
+        test_call_a![ffi::MemberConstReferenceDeleted];
+
+        test_copyable![ffi::MemberReference];
+        test_movable![ffi::MemberReference];
+        test_call_a![ffi::MemberReference];
+
+        test_copyable![ffi::MemberConstReference];
+        test_movable![ffi::MemberConstReference];
+        test_call_a![ffi::MemberConstReference];
+
+        test_movable![ffi::MemberRvalueReferenceDeleted];
+        test_call_a![ffi::MemberRvalueReferenceDeleted];
+
+        test_movable![ffi::MemberRvalueReference];
+        test_call_a![ffi::MemberRvalueReference];
+
+        test_call_a_as![ffi::BasePublicDeleted, ffi::PublicDeleted];
+
+        test_copyable![ffi::BasePublicDeletedDefault];
+        test_movable![ffi::BasePublicDeletedDefault];
+        test_call_a_as![ffi::BasePublicDeletedDefault, ffi::PublicDeletedDefault];
+
+        test_constructible![ffi::BasePublicDeletedCopy];
+        test_make_unique![ffi::BasePublicDeletedCopy];
+        test_call_a_as![ffi::BasePublicDeletedCopy, ffi::PublicDeletedCopy];
+
+        test_call_a_as![ffi::BasePublicDeletedCopyNoDefault, ffi::PublicDeletedCopyNoDefault];
+
+        test_constructible![ffi::BasePublicMoveDeletedCopy];
+        test_make_unique![ffi::BasePublicMoveDeletedCopy];
+        test_movable![ffi::BasePublicMoveDeletedCopy];
+        test_call_a_as![ffi::BasePublicMoveDeletedCopy, ffi::PublicMoveDeletedCopy];
+
+        test_constructible![ffi::BasePublicDeletedMove];
+        test_make_unique![ffi::BasePublicDeletedMove];
+        test_call_a_as![ffi::BasePublicDeletedMove, ffi::PublicDeletedMove];
+
+        test_call_a_as![ffi::BasePublicDeletedDestructor, ffi::PublicDeletedDestructor];
+
+        test_constructible![ffi::BasePublicDestructor];
+        test_make_unique![ffi::BasePublicDestructor];
+        test_copyable![ffi::BasePublicDestructor];
+        test_call_a_as![ffi::BasePublicDestructor, ffi::PublicDestructor];
+
+        test_call_a![ffi::MemberPublicDeleted];
+
+        test_copyable![ffi::MemberPublicDeletedDefault];
+        test_movable![ffi::MemberPublicDeletedDefault];
+        test_call_a![ffi::MemberPublicDeletedDefault];
+
+        test_constructible![ffi::MemberPublicDeletedCopy];
+        test_make_unique![ffi::MemberPublicDeletedCopy];
+        test_call_a![ffi::MemberPublicDeletedCopy];
+
+        test_call_a![ffi::MemberPublicDeletedCopyNoDefault];
+
+        test_constructible![ffi::MemberPublicMoveDeletedCopy];
+        test_make_unique![ffi::MemberPublicMoveDeletedCopy];
+        test_movable![ffi::MemberPublicMoveDeletedCopy];
+        test_call_a![ffi::MemberPublicMoveDeletedCopy];
+
+        test_constructible![ffi::MemberPublicDeletedMove];
+        test_make_unique![ffi::MemberPublicDeletedMove];
+        test_call_a![ffi::MemberPublicDeletedMove];
+
+        test_call_a![ffi::MemberPublicDeletedDestructor];
+
+        test_constructible![ffi::MemberPublicDestructor];
+        test_make_unique![ffi::MemberPublicDestructor];
+        test_copyable![ffi::MemberPublicDestructor];
+        test_call_a![ffi::MemberPublicDestructor];
+
+        test_call_a_as![ffi::BaseMemberPublicDeleted, ffi::MemberPublicDeleted];
+
+        test_copyable![ffi::BaseMemberPublicDeletedDefault];
+        test_movable![ffi::BaseMemberPublicDeletedDefault];
+        test_call_a_as![ffi::BaseMemberPublicDeletedDefault, ffi::MemberPublicDeletedDefault];
+
+        test_constructible![ffi::BaseMemberPublicDeletedCopy];
+        test_make_unique![ffi::BaseMemberPublicDeletedCopy];
+        test_call_a_as![ffi::BaseMemberPublicDeletedCopy, ffi::MemberPublicDeletedCopy];
+
+        test_call_a_as![ffi::BaseMemberPublicDeletedCopyNoDefault, ffi::MemberPublicDeletedCopyNoDefault];
+
+        test_constructible![ffi::BaseMemberPublicMoveDeletedCopy];
+        test_make_unique![ffi::BaseMemberPublicMoveDeletedCopy];
+        test_movable![ffi::BaseMemberPublicMoveDeletedCopy];
+        test_call_a_as![ffi::BaseMemberPublicMoveDeletedCopy, ffi::MemberPublicMoveDeletedCopy];
+
+        test_constructible![ffi::BaseMemberPublicDeletedMove];
+        test_make_unique![ffi::BaseMemberPublicDeletedMove];
+        test_call_a_as![ffi::BaseMemberPublicDeletedMove, ffi::MemberPublicDeletedMove];
+
+        test_call_a_as![ffi::BaseMemberPublicDeletedDestructor, ffi::MemberPublicDeletedDestructor];
+
+        test_constructible![ffi::BaseMemberPublicDestructor];
+        test_make_unique![ffi::BaseMemberPublicDestructor];
+        test_copyable![ffi::BaseMemberPublicDestructor];
+        test_call_a_as![ffi::BaseMemberPublicDestructor, ffi::MemberPublicDestructor];
+
+        test_call_a_as![ffi::BaseProtectedDeleted, ffi::ProtectedDeleted];
+
+        test_copyable![ffi::BaseProtectedDeletedDefault];
+        test_movable![ffi::BaseProtectedDeletedDefault];
+        test_call_a_as![ffi::BaseProtectedDeletedDefault, ffi::ProtectedDeletedDefault];
+
+        test_constructible![ffi::BaseProtectedDeletedCopy];
+        test_make_unique![ffi::BaseProtectedDeletedCopy];
+        test_call_a_as![ffi::BaseProtectedDeletedCopy, ffi::ProtectedDeletedCopy];
+
+        test_call_a_as![ffi::BaseProtectedDeletedCopyNoDefault, ffi::ProtectedDeletedCopyNoDefault];
+
+        test_constructible![ffi::BaseProtectedMoveDeletedCopy];
+        test_make_unique![ffi::BaseProtectedMoveDeletedCopy];
+        test_movable![ffi::BaseProtectedMoveDeletedCopy];
+        test_call_a_as![ffi::BaseProtectedMoveDeletedCopy, ffi::ProtectedMoveDeletedCopy];
+
+        test_constructible![ffi::BaseProtectedDeletedMove];
+        test_make_unique![ffi::BaseProtectedDeletedMove];
+        test_call_a_as![ffi::BaseProtectedDeletedMove, ffi::ProtectedDeletedMove];
+
+        test_call_a_as![ffi::BaseProtectedDeletedDestructor, ffi::ProtectedDeletedDestructor];
+
+        test_constructible![ffi::BaseProtectedDestructor];
+        test_make_unique![ffi::BaseProtectedDestructor];
+        test_copyable![ffi::BaseProtectedDestructor];
+        test_call_a_as![ffi::BaseProtectedDestructor, ffi::ProtectedDestructor];
+
+        test_call_a![ffi::MemberProtectedDeleted];
+
+        test_copyable![ffi::MemberProtectedDeletedDefault];
+        test_movable![ffi::MemberProtectedDeletedDefault];
+        test_call_a![ffi::MemberProtectedDeletedDefault];
+
+        test_constructible![ffi::MemberProtectedDeletedCopy];
+        test_make_unique![ffi::MemberProtectedDeletedCopy];
+        test_call_a![ffi::MemberProtectedDeletedCopy];
+
+        test_call_a![ffi::MemberProtectedDeletedCopyNoDefault];
+
+        test_constructible![ffi::MemberProtectedMoveDeletedCopy];
+        test_make_unique![ffi::MemberProtectedMoveDeletedCopy];
+        test_call_a![ffi::MemberProtectedMoveDeletedCopy];
+
+        test_constructible![ffi::MemberProtectedDeletedMove];
+        test_make_unique![ffi::MemberProtectedDeletedMove];
+        test_call_a![ffi::MemberProtectedDeletedMove];
+
+        test_call_a![ffi::MemberProtectedDeletedDestructor];
+
+        test_call_a![ffi::MemberProtectedDestructor];
+
+        test_call_a_as![ffi::BaseMemberProtectedDeleted, ffi::MemberProtectedDeleted];
+
+        test_copyable![ffi::BaseMemberProtectedDeletedDefault];
+        test_movable![ffi::BaseMemberProtectedDeletedDefault];
+        test_call_a_as![ffi::BaseMemberProtectedDeletedDefault, ffi::MemberProtectedDeletedDefault];
+
+        test_constructible![ffi::BaseMemberProtectedDeletedCopy];
+        test_make_unique![ffi::BaseMemberProtectedDeletedCopy];
+        test_call_a_as![ffi::BaseMemberProtectedDeletedCopy, ffi::MemberProtectedDeletedCopy];
+
+        test_call_a_as![ffi::BaseMemberProtectedDeletedCopyNoDefault, ffi::MemberProtectedDeletedCopyNoDefault];
+
+        test_constructible![ffi::BaseMemberProtectedMoveDeletedCopy];
+        test_make_unique![ffi::BaseMemberProtectedMoveDeletedCopy];
+        test_call_a_as![ffi::BaseMemberProtectedMoveDeletedCopy, ffi::MemberProtectedMoveDeletedCopy];
+
+        test_constructible![ffi::BaseMemberProtectedDeletedMove];
+        test_make_unique![ffi::BaseMemberProtectedDeletedMove];
+        test_call_a_as![ffi::BaseMemberProtectedDeletedMove, ffi::MemberProtectedDeletedMove];
+
+        test_call_a_as![ffi::BaseMemberProtectedDeletedDestructor, ffi::MemberProtectedDeletedDestructor];
+
+        test_call_a_as![ffi::BaseMemberProtectedDestructor, ffi::MemberProtectedDestructor];
+
+        test_call_a_as![ffi::BasePrivateDeleted, ffi::PrivateDeleted];
+
+        test_copyable![ffi::BasePrivateDeletedDefault];
+        test_movable![ffi::BasePrivateDeletedDefault];
+        test_call_a_as![ffi::BasePrivateDeletedDefault, ffi::PrivateDeletedDefault];
+
+        test_constructible![ffi::BasePrivateDeletedCopy];
+        test_make_unique![ffi::BasePrivateDeletedCopy];
+        test_call_a_as![ffi::BasePrivateDeletedCopy, ffi::PrivateDeletedCopy];
+
+        test_call_a_as![ffi::BasePrivateDeletedCopyNoDefault, ffi::PrivateDeletedCopyNoDefault];
+
+        test_constructible![ffi::BasePrivateMoveDeletedCopy];
+        test_make_unique![ffi::BasePrivateMoveDeletedCopy];
+        test_call_a_as![ffi::BasePrivateMoveDeletedCopy, ffi::PrivateMoveDeletedCopy];
+
+        test_constructible![ffi::BasePrivateDeletedMove];
+        test_make_unique![ffi::BasePrivateDeletedMove];
+        test_call_a_as![ffi::BasePrivateDeletedMove, ffi::PrivateDeletedMove];
+
+        test_call_a_as![ffi::BasePrivateDeletedDestructor, ffi::PrivateDeletedDestructor];
+
+        test_call_a_as![ffi::BasePrivateDestructor, ffi::PrivateDestructor];
+
+        test_call_a![ffi::MemberPrivateDeleted];
+
+        test_copyable![ffi::MemberPrivateDeletedDefault];
+        test_movable![ffi::MemberPrivateDeletedDefault];
+        test_call_a![ffi::MemberPrivateDeletedDefault];
+
+        test_constructible![ffi::MemberPrivateDeletedCopy];
+        test_make_unique![ffi::MemberPrivateDeletedCopy];
+        test_call_a![ffi::MemberPrivateDeletedCopy];
+
+        test_call_a![ffi::MemberPrivateDeletedCopyNoDefault];
+
+        test_constructible![ffi::MemberPrivateMoveDeletedCopy];
+        test_make_unique![ffi::MemberPrivateMoveDeletedCopy];
+        test_call_a![ffi::MemberPrivateMoveDeletedCopy];
+
+        test_constructible![ffi::MemberPrivateDeletedMove];
+        test_make_unique![ffi::MemberPrivateDeletedMove];
+        test_call_a![ffi::MemberPrivateDeletedMove];
+
+        test_call_a![ffi::MemberPrivateDeletedDestructor];
+
+        test_call_a![ffi::MemberPrivateDestructor];
+
+        test_call_a_as![ffi::BaseMemberPrivateDeleted, ffi::MemberPrivateDeleted];
+
+        test_copyable![ffi::BaseMemberPrivateDeletedDefault];
+        test_movable![ffi::BaseMemberPrivateDeletedDefault];
+        test_call_a_as![ffi::BaseMemberPrivateDeletedDefault, ffi::MemberPrivateDeletedDefault];
+
+        test_constructible![ffi::BaseMemberPrivateDeletedCopy];
+        test_make_unique![ffi::BaseMemberPrivateDeletedCopy];
+        test_call_a_as![ffi::BaseMemberPrivateDeletedCopy, ffi::MemberPrivateDeletedCopy];
+
+        test_call_a_as![ffi::BaseMemberPrivateDeletedCopyNoDefault, ffi::MemberPrivateDeletedCopyNoDefault];
+
+        test_constructible![ffi::BaseMemberPrivateMoveDeletedCopy];
+        test_make_unique![ffi::BaseMemberPrivateMoveDeletedCopy];
+        test_call_a_as![ffi::BaseMemberPrivateMoveDeletedCopy, ffi::MemberPrivateMoveDeletedCopy];
+
+        test_constructible![ffi::BaseMemberPrivateDeletedMove];
+        test_make_unique![ffi::BaseMemberPrivateDeletedMove];
+        test_call_a_as![ffi::BaseMemberPrivateDeletedMove, ffi::MemberPrivateDeletedMove];
+
+        test_call_a_as![ffi::BaseMemberPrivateDeletedDestructor, ffi::MemberPrivateDeletedDestructor];
+
+        test_call_a_as![ffi::BaseMemberPrivateDestructor, ffi::MemberPrivateDestructor];
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &[
+            "AllImplicitlyDefaulted",
+            "PublicDeleted",
+            "PublicDeletedDefault",
+            "PublicDeletedCopy",
+            "PublicDeletedCopyNoDefault",
+            "PublicMoveDeletedCopy",
+            "PublicDeletedMove",
+            "PublicDeletedDestructor",
+            "PublicDestructor",
+            "ProtectedDeleted",
+            "ProtectedDeletedDefault",
+            "ProtectedDeletedCopy",
+            "ProtectedDeletedCopyNoDefault",
+            "ProtectedMoveDeletedCopy",
+            "ProtectedDeletedMove",
+            "ProtectedDeletedDestructor",
+            "ProtectedDestructor",
+            "PrivateDeleted",
+            "PrivateDeletedDefault",
+            "PrivateDeletedCopy",
+            "PrivateDeletedCopyNoDefault",
+            "PrivateMoveDeletedCopy",
+            "PrivateDeletedMove",
+            "PrivateDeletedDestructor",
+            "PrivateDestructor",
+            "NonConstCopy",
+            "TwoCopy",
+            "MemberPointerDeleted",
+            "MemberConstPointerDeleted",
+            // TODO: Handle top-level const on C++ members correctly.
+            //"MemberConst",
+            "MemberReferenceDeleted",
+            "MemberConstReferenceDeleted",
+            "MemberReference",
+            "MemberConstReference",
+            "MemberRvalueReferenceDeleted",
+            "MemberRvalueReference",
+            "BasePublicDeleted",
+            "BasePublicDeletedDefault",
+            "BasePublicDeletedCopy",
+            "BasePublicDeletedCopyNoDefault",
+            "BasePublicMoveDeletedCopy",
+            "BasePublicDeletedMove",
+            "BasePublicDeletedDestructor",
+            "BasePublicDestructor",
+            "MemberPublicDeleted",
+            "MemberPublicDeletedDefault",
+            "MemberPublicDeletedCopy",
+            "MemberPublicDeletedCopyNoDefault",
+            "MemberPublicMoveDeletedCopy",
+            "MemberPublicDeletedMove",
+            "MemberPublicDeletedDestructor",
+            "MemberPublicDestructor",
+            "BaseMemberPublicDeleted",
+            "BaseMemberPublicDeletedDefault",
+            "BaseMemberPublicDeletedCopy",
+            "BaseMemberPublicDeletedCopyNoDefault",
+            "BaseMemberPublicMoveDeletedCopy",
+            "BaseMemberPublicDeletedMove",
+            "BaseMemberPublicDeletedDestructor",
+            "BaseMemberPublicDestructor",
+            "BaseProtectedDeleted",
+            "BaseProtectedDeletedDefault",
+            "BaseProtectedDeletedCopy",
+            "BaseProtectedDeletedCopyNoDefault",
+            "BaseProtectedMoveDeletedCopy",
+            "BaseProtectedDeletedMove",
+            "BaseProtectedDeletedDestructor",
+            "BaseProtectedDestructor",
+            "MemberProtectedDeleted",
+            "MemberProtectedDeletedDefault",
+            "MemberProtectedDeletedCopy",
+            "MemberProtectedDeletedCopyNoDefault",
+            "MemberProtectedMoveDeletedCopy",
+            "MemberProtectedDeletedMove",
+            "MemberProtectedDeletedDestructor",
+            "MemberProtectedDestructor",
+            "BaseMemberProtectedDeleted",
+            "BaseMemberProtectedDeletedDefault",
+            "BaseMemberProtectedDeletedCopy",
+            "BaseMemberProtectedDeletedCopyNoDefault",
+            "BaseMemberProtectedMoveDeletedCopy",
+            "BaseMemberProtectedDeletedMove",
+            "BaseMemberProtectedDeletedDestructor",
+            "BaseMemberProtectedDestructor",
+            "BasePrivateDeleted",
+            "BasePrivateDeletedDefault",
+            "BasePrivateDeletedCopy",
+            "BasePrivateDeletedCopyNoDefault",
+            "BasePrivateMoveDeletedCopy",
+            "BasePrivateDeletedMove",
+            "BasePrivateDeletedDestructor",
+            "BasePrivateDestructor",
+            "MemberPrivateDeleted",
+            "MemberPrivateDeletedDefault",
+            "MemberPrivateDeletedCopy",
+            "MemberPrivateDeletedCopyNoDefault",
+            "MemberPrivateMoveDeletedCopy",
+            "MemberPrivateDeletedMove",
+            "MemberPrivateDeletedDestructor",
+            "MemberPrivateDestructor",
+            "BaseMemberPrivateDeleted",
+            "BaseMemberPrivateDeletedDefault",
+            "BaseMemberPrivateDeletedCopy",
+            "BaseMemberPrivateDeletedCopyNoDefault",
+            "BaseMemberPrivateMoveDeletedCopy",
+            "BaseMemberPrivateDeletedMove",
+            "BaseMemberPrivateDeletedDestructor",
+            "BaseMemberPrivateDestructor",
+        ],
+        &[],
+    );
+}
+
+#[test]
+/// Test that destructors hidden in various places are correctly called.
+///
+/// Some types are excluded because we know they behave poorly due to
+/// https://github.com/google/autocxx/issues/829.
+fn test_tricky_destructors() {
+    let cxx = "";
+    let hdr = indoc! {"
+        #include <stdio.h>
+        #include <stdlib.h>
+        // A simple type to let Rust verify the destructor is run.
+        struct DestructorFlag {
+            DestructorFlag() = default;
+            DestructorFlag(const DestructorFlag&) = default;
+            DestructorFlag(DestructorFlag&&) = default;
+
+            ~DestructorFlag() {
+                if (!flag) return;
+                if (*flag) {
+                    fprintf(stderr, \"DestructorFlag is already set\\n\");
+                    abort();
+                }
+                *flag = true;
+                // Note we deliberately do NOT clear the value of `flag`, to catch Rust calling
+                // this destructor twice.
+            }
+
+            bool *flag = nullptr;
+        };
+
+        struct ImplicitlyDefaulted {
+            DestructorFlag flag;
+
+            void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
+        };
+        struct ExplicitlyDefaulted {
+            ExplicitlyDefaulted() = default;
+            ~ExplicitlyDefaulted() = default;
+
+            DestructorFlag flag;
+
+            void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
+        };
+        struct Explicit {
+            Explicit() = default;
+            ~Explicit() {}
+
+            DestructorFlag flag;
+
+            void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
+        };
+
+        struct BaseImplicitlyDefaulted : public ImplicitlyDefaulted {
+            void set_flag(bool *flag_pointer) { ImplicitlyDefaulted::set_flag(flag_pointer); }
+        };
+        struct BaseExplicitlyDefaulted : public ExplicitlyDefaulted {
+            void set_flag(bool *flag_pointer) { ExplicitlyDefaulted::set_flag(flag_pointer); }
+        };
+        struct BaseExplicit : public Explicit {
+            void set_flag(bool *flag_pointer) { Explicit::set_flag(flag_pointer); }
+        };
+
+        struct MemberImplicitlyDefaulted {
+            ImplicitlyDefaulted member;
+
+            void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
+        };
+        struct MemberExplicitlyDefaulted {
+            ExplicitlyDefaulted member;
+
+            void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
+        };
+        struct MemberExplicit {
+            Explicit member;
+
+            void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
+        };
+
+        struct BaseMemberImplicitlyDefaulted : public MemberImplicitlyDefaulted {
+            void set_flag(bool *flag_pointer) { MemberImplicitlyDefaulted::set_flag(flag_pointer); }
+        };
+        struct BaseMemberExplicitlyDefaulted : public MemberExplicitlyDefaulted {
+            void set_flag(bool *flag_pointer) { MemberExplicitlyDefaulted::set_flag(flag_pointer); }
+        };
+        struct BaseMemberExplicit : public MemberExplicit {
+            void set_flag(bool *flag_pointer) { MemberExplicit::set_flag(flag_pointer); }
+        };
+    "};
+    let rs = quote! {
+        macro_rules! test_type {
+            [$t:ty] => {
+                let mut unique_t = <$t>::new().within_unique_ptr();
+                let mut destructor_flag = false;
+                unsafe {
+                    unique_t.pin_mut().set_flag(&mut destructor_flag);
+                }
+                std::mem::drop(unique_t);
+                assert!(destructor_flag, "Destructor did not run with make_unique for {}", quote::quote!{$t});
+
+                moveit! {
+                    let mut moveit_t = <$t>::new();
+                }
+                let mut destructor_flag = false;
+                unsafe {
+                    moveit_t.as_mut().set_flag(&mut destructor_flag);
+                }
+                std::mem::drop(moveit_t);
+                assert!(destructor_flag, "Destructor did not run with moveit for {}", quote::quote!{$t});
+            }
+        }
+
+        test_type![ffi::ImplicitlyDefaulted];
+        test_type![ffi::ExplicitlyDefaulted];
+        test_type![ffi::Explicit];
+        test_type![ffi::BaseImplicitlyDefaulted];
+        test_type![ffi::BaseExplicitlyDefaulted];
+        test_type![ffi::BaseExplicit];
+        test_type![ffi::MemberImplicitlyDefaulted];
+        test_type![ffi::MemberExplicitlyDefaulted];
+        test_type![ffi::MemberExplicit];
+        test_type![ffi::BaseMemberImplicitlyDefaulted];
+        test_type![ffi::BaseMemberExplicitlyDefaulted];
+        test_type![ffi::BaseMemberExplicit];
+    };
+    run_test(
+        cxx,
+        hdr,
+        rs,
+        &[
+            "DestructorFlag",
+            "ImplicitlyDefaulted",
+            "ExplicitlyDefaulted",
+            "Explicit",
+            "BaseImplicitlyDefaulted",
+            "BaseExplicitlyDefaulted",
+            "BaseExplicit",
+            "MemberImplicitlyDefaulted",
+            "MemberExplicitlyDefaulted",
+            "MemberExplicit",
+            "BaseMemberImplicitlyDefaulted",
+            "BaseMemberExplicitlyDefaulted",
+            "BaseMemberExplicit",
+        ],
+        &[],
+    );
+}
+
+#[test]
+fn test_concretize() {
+    let hdr = indoc! {"
+        #include <string>
+        template<typename CONTENTS>
+        class Container {
+        private:
+            CONTENTS* contents;
+        };
+        struct B {
+            std::string a;
+        };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! {
+            concrete!("Container<B>", ContainerOfB)
+            generate!("B")
+        },
+        None,
+        None,
+        Some(quote! {
+            struct HasAField {
+                contents: ffi::ContainerOfB
+            }
+        }),
+    );
+}
+
+#[test]
+fn test_doc_comments_survive() {
+    let hdr = indoc! {"
+        #include <cstdint>
+        /// Struct line A
+        /// Struct line B
+        struct A { int b; };
+
+        /// POD struct line A
+        /// POD struct line B
+        struct B {
+            /// Field line A
+            /// Field line B
+            uint32_t b;
+
+            /// Method line A
+            /// Method line B
+            void foo() {}
+        };
+
+        /// Enum line A
+        /// Enum line B
+        enum C {
+            /// Variant line A
+            /// Variant line B
+            VARIANT,
+        };
+
+        /// Function line A
+        /// Function line B
+        inline void D() {}
+    "};
+
+    let expected_messages = [
+        "Struct",
+        "POD struct",
+        "Field",
+        "Method",
+        "Enum",
+        "Variant",
+        "Function",
+    ]
+    .into_iter()
+    .flat_map(|l| [format!("{} line A", l), format!("{} line B", l)])
+    .collect_vec();
+
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        directives_from_lists(&["A", "C", "D"], &["B"], None),
+        None,
+        Some(make_string_finder(expected_messages)),
+        None,
+    );
+}
+
+#[test]
+fn optional_param_in_copy_constructor() {
+    let hdr = indoc! {"
+        struct A {
+            A(const A &other, bool optional_arg = false);
+        };
+    "};
+    run_test("", hdr, quote! {}, &["A"], &[]);
+}
+
+#[test]
+fn param_in_copy_constructor() {
+    let hdr = indoc! {"
+        struct A {
+            A(const A &other, bool arg);
+        };
+    "};
+    run_test("", hdr, quote! {}, &["A"], &[]);
+}
+
+#[test]
+fn test_variadic() {
+    let hdr = indoc! {"
+        class SomeClass{
+        public:
+            inline void foo(int, ... ) {}
+        };
+    "};
+    run_test("", hdr, quote! {}, &["SomeClass"], &[]);
+}
+
+#[test]
+fn test_typedef_to_enum() {
+    let hdr = indoc! {"
+        enum b {};
+        class c {
+        public:
+          typedef b d;
+          d e();
+        };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_typedef_to_ns_enum() {
+    let hdr = indoc! {"
+        namespace a {
+        enum b {};
+        class c {
+        public:
+          typedef b d;
+          d e();
+        };
+        } // namespace
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_typedef_unsupported_type_pub() {
+    let hdr = indoc! {"
+        #include <set>
+        namespace NS{
+            class cls{
+                public:
+                    typedef std::set<int> InnerType;
+                };
+        }
+    "};
+
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_ns!("NS") },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_typedef_unsupported_type_pri() {
+    let hdr = indoc! {"
+        #include <set>
+        namespace NS{
+            class cls{
+                private:
+                    typedef std::set<int> InnerType;
+                };
+        }
+    "};
+
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_ns!("NS") },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_array_trouble1() {
+    let hdr = indoc! {"
+        namespace a {
+        template <typename b> struct array {
+          typedef b c;
+          typedef c d;
+        };
+        } // namespace a
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_array_trouble2() {
+    let hdr = indoc! {"
+        template <typename b> struct array {
+          typedef b c;
+          typedef c d;
+        };
+    "};
+    run_test("", hdr, quote! {}, &["array_d"], &[]);
+}
+
+#[test]
+fn test_issue_1087a() {
+    let hdr = indoc! {"
+        template <typename _CharT> class a {
+          _CharT b;
+        };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_issue_1087b() {
+    let hdr = indoc! {"
+        template <typename _CharT> class a {
+          typedef _CharT b;
+          b c;
+        };
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_issue_1087c() {
+    let hdr = indoc! {"
+        namespace {
+        namespace {
+        template <typename _CharT> class a {
+          typedef _CharT b;
+          b c;
+        };
+        }
+        }
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_issue_1089() {
+    let hdr = indoc! {"
+        namespace a {
+        template <typename c, c> struct d;
+        template <bool, typename, typename> struct ab;
+        inline namespace {
+        namespace ac {
+        template <typename, template <typename> class, typename> struct bh;
+        template <template <typename> class ad, typename... bi>
+        using bj = bh<void, ad, bi...>;
+        template <typename ad> using bk = typename ad::b;
+        template <typename> struct bm;
+        } // namespace ac
+        template <typename ad>
+        struct b : ab<ac::bj<ac::bk, ad>::e, ac::bm<ad>, d<bool, ad ::e>>::bg {};
+        } // namespace
+        } // namespace a
+    "};
+    run_test_ex(
+        "",
+        hdr,
+        quote! {},
+        quote! { generate_all!() },
+        None,
+        None,
+        None,
+    );
+}
+
+#[test]
+fn test_pass_rust_str_and_return_struct() {
+    let cxx = indoc! {"
+        A take_str_return_struct(rust::Str) {
+            A a;
+            return a;
+        }
+    "};
+    let hdr = indoc! {"
+        #include <cxx.h>
+        struct A {};
+        A take_str_return_struct(rust::Str);
+    "};
+    let rs = quote! {
+        ffi::take_str_return_struct("hi");
+    };
+    run_test(cxx, hdr, rs, &["take_str_return_struct"], &[]);
+}
+
+#[test]
+fn test_issue_1065a() {
+    let hdr = indoc! {"
+        #include <memory>
+        #include <vector>
+
+        template <typename at> class au {
+        std::unique_ptr<at> aw;
+        };
+        class bb;
+        using bc = au<bb>;
+        class RenderFrameHost {
+        public:
+        virtual std::vector<bc> &bd() = 0;
+        virtual ~RenderFrameHost() {}
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["RenderFrameHost"], &[]);
+}
+
+#[test]
+fn test_issue_1065b() {
+    let hdr = indoc! {"
+        #include <memory>
+        #include <vector>
+
+        class bb;
+        using bc = std::unique_ptr<bb>;
+        class RenderFrameHost {
+        public:
+        virtual std::vector<bc> &bd() = 0;
+        virtual ~RenderFrameHost() {}
+        };
+    "};
+    let rs = quote! {};
+    run_test("", hdr, rs, &["RenderFrameHost"], &[]);
+}
+
+// Yet to test:
+// - Ifdef
+// - Out param pointers
+// - ExcludeUtilities
+// - Struct fields which are typedefs
+// Negative tests:
+// - Private methods
+// - Private fields
diff --git a/integration-tests/tests/lib.rs b/integration-tests/tests/lib.rs
new file mode 100644
index 0000000..17f076a
--- /dev/null
+++ b/integration-tests/tests/lib.rs
@@ -0,0 +1,11 @@
+// Copyright 2021 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 builder_modifiers;
+mod code_checkers;
+mod integration_test;