Snap for 8564071 from f427b2a756cc7e3acbf5123e3fcdd7cd93b2465f to mainline-cellbroadcast-release

Change-Id: I245b3afcc9a7ab69273877c796c47ad2bef9487f
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3fafd9b..0b82cd9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,6 +54,7 @@
   buck:
     name: Buck
     runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
     steps:
       - uses: actions/checkout@v2
       - uses: dtolnay/rust-toolchain@stable
@@ -80,6 +81,7 @@
   bazel:
     name: Bazel
     runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
     steps:
       - uses: actions/checkout@v2
       - name: Install Bazel
diff --git a/Android.bp b/Android.bp
index 014c937..05ef387 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,13 @@
     ],
     shared_libs: ["libc++"],
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+        "com.android.compos",
+        "com.android.virt",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_library_static {
@@ -60,8 +67,11 @@
     srcs: ["src/cxx.cc"],
     apex_available: [
         "//apex_available:platform",
-        "com.android.bluetooth.updatable",
+        "com.android.bluetooth",
+        "com.android.compos",
+        "com.android.virt",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library_static {
diff --git a/BUCK b/BUCK
index da6fcb2..86174e9 100644
--- a/BUCK
+++ b/BUCK
@@ -25,19 +25,19 @@
 cxx_library(
     name = "core",
     srcs = ["src/cxx.cc"],
-    visibility = ["PUBLIC"],
-    header_namespace = "rust",
     exported_headers = {
         "cxx.h": "include/cxx.h",
     },
     exported_linker_flags = ["-lstdc++"],
+    header_namespace = "rust",
+    visibility = ["PUBLIC"],
 )
 
 rust_library(
     name = "macro",
     srcs = glob(["macro/src/**"]),
-    proc_macro = True,
     crate = "cxxbridge_macro",
+    proc_macro = True,
     deps = [
         "//third-party:proc-macro2",
         "//third-party:quote",
diff --git a/BUILD b/BUILD
index 24a1c8b..c2c2edf 100644
--- a/BUILD
+++ b/BUILD
@@ -1,5 +1,5 @@
 load("@rules_cc//cc:defs.bzl", "cc_library")
-load("//tools/bazel:rust.bzl", "rust_binary", "rust_library")
+load("@rules_rust//rust:rust.bzl", "rust_binary", "rust_library")
 
 rust_library(
     name = "cxx",
diff --git a/Cargo.toml b/Cargo.toml
index e2b189e..0414c72 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxx"
-version = "1.0.42" # remember to update html_root_url
+version = "1.0.54" # remember to update html_root_url
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 links = "cxxbridge1"
@@ -21,15 +21,15 @@
 "c++20" = ["cxxbridge-flags/c++20"]
 
 [dependencies]
-cxxbridge-macro = { version = "=1.0.42", path = "macro" }
+cxxbridge-macro = { version = "=1.0.54", path = "macro" }
 link-cplusplus = "1.0"
 
 [build-dependencies]
 cc = "1.0.49"
-cxxbridge-flags = { version = "=1.0.42", path = "flags", default-features = false }
+cxxbridge-flags = { version = "=1.0.54", path = "flags", default-features = false }
 
 [dev-dependencies]
-cxx-build = { version = "=1.0.42", path = "gen/build" }
+cxx-build = { version = "=1.0.54", path = "gen/build" }
 cxx-gen = { version = "0.7", path = "gen/lib" }
 cxx-test-suite = { version = "0", path = "tests/ffi" }
 rustversion = "1.0"
diff --git a/METADATA b/METADATA
index 2b3490c..85611d6 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
 name: "cxx"
-description:
-    "Safe interop between Rust and C++"
-
+description: "Safe interop between Rust and C++"
 third_party {
   url {
     type: HOMEPAGE
@@ -11,7 +9,11 @@
     type: GIT
     value: "https://github.com/dtolnay/cxx.git"
   }
-  version: "4ab117115718908768df8366ac130bbbb3478331"
-  last_upgrade_date { year: 2021 month: 2 day: 17 }
+  version: "36d9ac1fab726e14305ce1919ebf8a3d64949d30"
   license_type: NOTICE
+  last_upgrade_date {
+    year: 2021
+    month: 9
+    day: 23
+  }
 }
diff --git a/WORKSPACE b/WORKSPACE
index 17a0af5..08aacf2 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,26 +1,30 @@
 workspace(name = "cxx.rs")
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-load("//tools/bazel:vendor.bzl", "vendor")
 
 http_archive(
     name = "rules_rust",
-    sha256 = "e6d835ee673f388aa5b62dc23d82db8fc76497e93fa47d8a4afe97abaf09b10d",
-    strip_prefix = "rules_rust-f37b9d6a552e9412285e627f30cb124e709f4f7a",
+    sha256 = "697a6f4f2adbd1b00f792346d6eca4cd45f691be63069c7d7ebf4fcf82a377a8",
+    strip_prefix = "rules_rust-8bad4c5e4e53d9f6f8d4d5228e26a44d92f37ab2",
     urls = [
-        # Master branch as of 2021-01-27
-        "https://github.com/bazelbuild/rules_rust/archive/f37b9d6a552e9412285e627f30cb124e709f4f7a.tar.gz",
+        # Master branch as of 2021-04-11
+        "https://github.com/bazelbuild/rules_rust/archive/8bad4c5e4e53d9f6f8d4d5228e26a44d92f37ab2.tar.gz",
     ],
 )
 
 load("@rules_rust//rust:repositories.bzl", "rust_repositories")
 
+RUST_VERSION = "1.54.0"
+
 rust_repositories(
     edition = "2018",
-    version = "1.50.0",
+    version = RUST_VERSION,
 )
 
+load("//tools/bazel:vendor.bzl", "vendor")
+
 vendor(
     name = "third-party",
     lockfile = "//third-party:Cargo.lock",
+    cargo_version = RUST_VERSION,
 )
diff --git a/book/src/binding/str.md b/book/src/binding/str.md
index a4820aa..9c1e0a7 100644
--- a/book/src/binding/str.md
+++ b/book/src/binding/str.md
@@ -30,6 +30,7 @@
   const char *data() const noexcept;
   size_t size() const noexcept;
   size_t length() const noexcept;
+  bool empty() const noexcept;
 
   using iterator = const char *;
   using const_iterator = const char *;
diff --git a/book/src/binding/string.md b/book/src/binding/string.md
index a7d0790..d564e00 100644
--- a/book/src/binding/string.md
+++ b/book/src/binding/string.md
@@ -23,6 +23,10 @@
   String(const char *);
   String(const char *, size_t);
 
+  // Throws std::invalid_argument if not utf-16.
+  String(const char16_t *);
+  String(const char16_t *, size_t);
+
   String &operator=(const String &) noexcept;
   String &operator=(String &&) noexcept;
 
@@ -32,9 +36,13 @@
   const char *data() const noexcept;
   size_t size() const noexcept;
   size_t length() const noexcept;
+  bool empty() const noexcept;
 
   const char *c_str() noexcept;
 
+  size_t capacity() const noexcept;
+  void reserve(size_t new_cap) noexcept;
+
   using iterator = char *;
   iterator begin() noexcept;
   iterator end() noexcept;
diff --git a/book/src/build/bazel.md b/book/src/build/bazel.md
index 08edb19..8f91055 100644
--- a/book/src/build/bazel.md
+++ b/book/src/build/bazel.md
@@ -70,7 +70,7 @@
 # demo/BUILD
 
 load("@rules_cc//cc:defs.bzl", "cc_library")
-load("//tools/bazel:rust.bzl", "rust_binary")
+load("@rules_rust//rust:rust.bzl", "rust_binary")
 load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_binary(
diff --git a/book/src/build/cmake.md b/book/src/build/cmake.md
index ed3cb61..4b50746 100644
--- a/book/src/build/cmake.md
+++ b/book/src/build/cmake.md
@@ -22,3 +22,10 @@
   - Tested on Windows 10 with MSVC, and on Linux
 
 ---
+
+- **<https://github.com/trondhe/rusty_cmake>**
+
+  - Alias target that can be linked into a C++ project
+  - Tested on Windows 10 with GNU target, and on Linux
+
+---
diff --git a/build.rs b/build.rs
index f799441..a953639 100644
--- a/build.rs
+++ b/build.rs
@@ -28,6 +28,12 @@
                 rustc.version,
             );
         }
+
+        if rustc.minor < 52 {
+            // #![deny(unsafe_op_in_unsafe_fn)].
+            // https://github.com/rust-lang/rust/issues/71668
+            println!("cargo:rustc-cfg=no_unsafe_op_in_unsafe_fn_lint");
+        }
     }
 }
 
diff --git a/demo/BUILD b/demo/BUILD
index cce8119..4ab5ecb 100644
--- a/demo/BUILD
+++ b/demo/BUILD
@@ -1,5 +1,5 @@
 load("@rules_cc//cc:defs.bzl", "cc_library")
-load("//tools/bazel:rust.bzl", "rust_binary")
+load("@rules_rust//rust:rust.bzl", "rust_binary")
 load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_binary(
diff --git a/flags/Cargo.toml b/flags/Cargo.toml
index 87c796c..baf1157 100644
--- a/flags/Cargo.toml
+++ b/flags/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxxbridge-flags"
-version = "1.0.42"
+version = "1.0.54"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
diff --git a/gen/build/Cargo.toml b/gen/build/Cargo.toml
index 33f17df..393fc1c 100644
--- a/gen/build/Cargo.toml
+++ b/gen/build/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxx-build"
-version = "1.0.42"
+version = "1.0.54"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
@@ -21,7 +21,7 @@
 proc-macro2 = { version = "1.0.26", default-features = false, features = ["span-locations"] }
 quote = { version = "1.0", default-features = false }
 scratch = "1.0"
-syn = { version = "1.0.68", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
+syn = { version = "1.0.70", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
 
 [dev-dependencies]
 cxx-gen = { version = "0.7", path = "../lib" }
diff --git a/gen/build/src/lib.rs b/gen/build/src/lib.rs
index 63b2cf6..b8a463c 100644
--- a/gen/build/src/lib.rs
+++ b/gen/build/src/lib.rs
@@ -51,6 +51,7 @@
     clippy::doc_markdown,
     clippy::drop_copy,
     clippy::enum_glob_use,
+    clippy::if_same_then_else,
     clippy::inherent_to_string,
     clippy::items_after_statements,
     clippy::let_underscore_drop,
diff --git a/gen/cmd/Cargo.toml b/gen/cmd/Cargo.toml
index 7db0206..4b3a299 100644
--- a/gen/cmd/Cargo.toml
+++ b/gen/cmd/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxxbridge-cmd"
-version = "1.0.42"
+version = "1.0.54"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
@@ -20,7 +20,7 @@
 codespan-reporting = "0.11"
 proc-macro2 = { version = "1.0.26", default-features = false, features = ["span-locations"] }
 quote = { version = "1.0", default-features = false }
-syn = { version = "1.0.68", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
+syn = { version = "1.0.70", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
diff --git a/gen/cmd/src/main.rs b/gen/cmd/src/main.rs
index f419dad..1c15db6 100644
--- a/gen/cmd/src/main.rs
+++ b/gen/cmd/src/main.rs
@@ -3,6 +3,7 @@
     clippy::cognitive_complexity,
     clippy::default_trait_access,
     clippy::enum_glob_use,
+    clippy::if_same_then_else,
     clippy::inherent_to_string,
     clippy::items_after_statements,
     clippy::large_enum_variant,
diff --git a/gen/lib/Cargo.toml b/gen/lib/Cargo.toml
index ff33d97..37d8168 100644
--- a/gen/lib/Cargo.toml
+++ b/gen/lib/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxx-gen"
-version = "0.7.42"
+version = "0.7.54"
 authors = ["Adrian Taylor <adetaylor@chromium.org>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
@@ -15,7 +15,7 @@
 codespan-reporting = "0.11"
 proc-macro2 = { version = "1.0.26", default-features = false, features = ["span-locations"] }
 quote = { version = "1.0", default-features = false }
-syn = { version = "1.0.68", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
+syn = { version = "1.0.70", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
diff --git a/gen/lib/src/lib.rs b/gen/lib/src/lib.rs
index e3eca5e..411953b 100644
--- a/gen/lib/src/lib.rs
+++ b/gen/lib/src/lib.rs
@@ -12,6 +12,7 @@
     clippy::cast_sign_loss,
     clippy::default_trait_access,
     clippy::enum_glob_use,
+    clippy::if_same_then_else,
     clippy::inherent_to_string,
     clippy::items_after_statements,
     clippy::match_bool,
diff --git a/gen/src/builtin.rs b/gen/src/builtin.rs
index eaaa08d..7ac9209 100644
--- a/gen/src/builtin.rs
+++ b/gen/src/builtin.rs
@@ -30,6 +30,7 @@
     pub relocatable: bool,
     pub friend_impl: bool,
     pub is_complete: bool,
+    pub destroy: bool,
     pub deleter_if: bool,
     pub content: Content<'a>,
 }
@@ -334,6 +335,14 @@
         writeln!(out, "}};");
     }
 
+    if builtin.destroy {
+        out.next_section();
+        writeln!(out, "template <typename T>");
+        writeln!(out, "void destroy(T *ptr) {{");
+        writeln!(out, "  ptr->~T();");
+        writeln!(out, "}}");
+    }
+
     if builtin.deleter_if {
         out.next_section();
         writeln!(out, "template <bool> struct deleter_if {{");
diff --git a/gen/src/check.rs b/gen/src/check.rs
index 35929ad..15add20 100644
--- a/gen/src/check.rs
+++ b/gen/src/check.rs
@@ -4,7 +4,7 @@
 use quote::{quote, quote_spanned};
 use std::path::{Component, Path};
 
-pub(super) use crate::syntax::check::typecheck;
+pub(super) use crate::syntax::check::{typecheck, Generator};
 
 pub(super) fn precheck(cx: &mut Errors, apis: &[Api], opt: &Opt) {
     if !opt.allow_dot_includes {
diff --git a/gen/src/error.rs b/gen/src/error.rs
index 2c8287f..3672e26 100644
--- a/gen/src/error.rs
+++ b/gen/src/error.rs
@@ -87,12 +87,11 @@
 
     impl<E: StdError> Display for Report<E> {
         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-            Display::fmt(&self.0, formatter)?;
+            write!(formatter, "{}", self.0)?;
             let mut error: &dyn StdError = &self.0;
 
             while let Some(cause) = error.source() {
-                formatter.write_str("\n\nCaused by:\n    ")?;
-                Display::fmt(cause, formatter)?;
+                write!(formatter, "\n\nCaused by:\n    {}", cause)?;
                 error = cause;
             }
 
diff --git a/gen/src/mod.rs b/gen/src/mod.rs
index 3d12c71..d8b90d0 100644
--- a/gen/src/mod.rs
+++ b/gen/src/mod.rs
@@ -130,7 +130,8 @@
     let ref types = Types::collect(errors, apis);
     check::precheck(errors, apis, opt);
     errors.propagate()?;
-    check::typecheck(errors, apis, types);
+    let generator = check::Generator::Build;
+    check::typecheck(errors, apis, types, generator);
     errors.propagate()?;
 
     // Some callers may wish to generate both header and implementation from the
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 9f9c039..a3b9c9f 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -9,8 +9,8 @@
 use crate::syntax::symbol::Symbol;
 use crate::syntax::trivial::{self, TrivialReason};
 use crate::syntax::{
-    derive, mangle, Api, Enum, ExternFn, ExternType, Pair, Signature, Struct, Trait, Type,
-    TypeAlias, Types, Var,
+    derive, mangle, Api, Doc, Enum, EnumRepr, ExternFn, ExternType, Pair, Signature, Struct, Trait,
+    Type, TypeAlias, Types, Var,
 };
 use proc_macro2::Ident;
 
@@ -101,10 +101,10 @@
             }
             Api::Enum(enm) => {
                 out.next_section();
-                if out.types.cxx.contains(&enm.name.rust) {
-                    check_enum(out, enm);
-                } else {
+                if !out.types.cxx.contains(&enm.name.rust) {
                     write_enum(out, enm);
+                } else if !enm.variants_from_header {
+                    check_enum(out, enm);
                 }
             }
             Api::RustType(ety) => {
@@ -249,14 +249,24 @@
         writeln!(out, "{};", field.name.cxx);
     }
 
-    writeln!(out);
+    out.next_section();
 
     for method in methods {
+        if !method.doc.is_empty() {
+            out.next_section();
+        }
+        for line in method.doc.to_string().lines() {
+            writeln!(out, "  //{}", line);
+        }
         write!(out, "  ");
         let sig = &method.sig;
         let local_name = method.name.cxx.to_string();
-        write_rust_function_shim_decl(out, &local_name, sig, false);
+        let indirect_call = false;
+        write_rust_function_shim_decl(out, &local_name, sig, indirect_call);
         writeln!(out, ";");
+        if !method.doc.is_empty() {
+            out.next_section();
+        }
     }
 
     if operator_eq {
@@ -307,8 +317,12 @@
 }
 
 fn write_enum_decl(out: &mut OutFile, enm: &Enum) {
+    let repr = match &enm.repr {
+        EnumRepr::Foreign { .. } => return,
+        EnumRepr::Native { atom, .. } => *atom,
+    };
     write!(out, "enum class {} : ", enm.name.cxx);
-    write_atom(out, enm.repr);
+    write_atom(out, repr);
     writeln!(out, ";");
 }
 
@@ -332,12 +346,22 @@
         ety.name.cxx,
     );
 
-    for method in methods {
+    for (i, method) in methods.iter().enumerate() {
+        if i > 0 && !method.doc.is_empty() {
+            out.next_section();
+        }
+        for line in method.doc.to_string().lines() {
+            writeln!(out, "  //{}", line);
+        }
         write!(out, "  ");
         let sig = &method.sig;
         let local_name = method.name.cxx.to_string();
-        write_rust_function_shim_decl(out, &local_name, sig, false);
+        let indirect_call = false;
+        write_rust_function_shim_decl(out, &local_name, sig, indirect_call);
         writeln!(out, ";");
+        if !method.doc.is_empty() {
+            out.next_section();
+        }
     }
 
     writeln!(out, "  ~{}() = delete;", ety.name.cxx);
@@ -356,6 +380,10 @@
 }
 
 fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
+    let repr = match &enm.repr {
+        EnumRepr::Foreign { .. } => return,
+        EnumRepr::Native { atom, .. } => *atom,
+    };
     out.set_namespace(&enm.name.namespace);
     let guard = format!("CXXBRIDGE1_ENUM_{}", enm.name.to_symbol());
     writeln!(out, "#ifndef {}", guard);
@@ -364,7 +392,7 @@
         writeln!(out, "//{}", line);
     }
     write!(out, "enum class {} : ", enm.name.cxx);
-    write_atom(out, enm.repr);
+    write_atom(out, repr);
     writeln!(out, " {{");
     for variant in &enm.variants {
         for line in variant.doc.to_string().lines() {
@@ -377,6 +405,10 @@
 }
 
 fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
+    let repr = match &enm.repr {
+        EnumRepr::Foreign { .. } => return,
+        EnumRepr::Native { atom, .. } => *atom,
+    };
     out.set_namespace(&enm.name.namespace);
     out.include.type_traits = true;
     writeln!(
@@ -385,11 +417,11 @@
         enm.name.cxx,
     );
     write!(out, "static_assert(sizeof({}) == sizeof(", enm.name.cxx);
-    write_atom(out, enm.repr);
+    write_atom(out, repr);
     writeln!(out, "), \"incorrect size\");");
     for variant in &enm.variants {
         write!(out, "static_assert(static_cast<");
-        write_atom(out, enm.repr);
+        write_atom(out, repr);
         writeln!(
             out,
             ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
@@ -824,7 +856,8 @@
 
     out.next_section();
     let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
-    write_rust_function_shim_impl(out, &c_trampoline, f, &r_trampoline, indirect_call);
+    let doc = Doc::new();
+    write_rust_function_shim_impl(out, &c_trampoline, f, &doc, &r_trampoline, indirect_call);
 }
 
 fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
@@ -894,9 +927,6 @@
 
 fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
     out.set_namespace(&efn.name.namespace);
-    for line in efn.doc.to_string().lines() {
-        writeln!(out, "//{}", line);
-    }
     let local_name = match &efn.sig.receiver {
         None => efn.name.cxx.to_string(),
         Some(receiver) => format!(
@@ -905,9 +935,10 @@
             efn.name.cxx,
         ),
     };
+    let doc = &efn.doc;
     let invoke = mangle::extern_fn(efn, out.types);
     let indirect_call = false;
-    write_rust_function_shim_impl(out, &local_name, efn, &invoke, indirect_call);
+    write_rust_function_shim_impl(out, &local_name, efn, doc, &invoke, indirect_call);
 }
 
 fn write_rust_function_shim_decl(
@@ -947,6 +978,7 @@
     out: &mut OutFile,
     local_name: &str,
     sig: &Signature,
+    doc: &Doc,
     invoke: &Symbol,
     indirect_call: bool,
 ) {
@@ -954,6 +986,12 @@
         // We've already defined this inside the struct.
         return;
     }
+    if sig.receiver.is_none() {
+        // Member functions already documented at their declaration.
+        for line in doc.to_string().lines() {
+            writeln!(out, "//{}", line);
+        }
+    }
     write_rust_function_shim_decl(out, local_name, sig, indirect_call);
     if out.header {
         writeln!(out, ";");
@@ -1429,7 +1467,7 @@
     );
     writeln!(
         out,
-        "void cxxbridge1$rust_vec${}$reserve_total(::rust::Vec<{}> *ptr, ::std::size_t cap) noexcept;",
+        "void cxxbridge1$rust_vec${}$reserve_total(::rust::Vec<{}> *ptr, ::std::size_t new_cap) noexcept;",
         instance, inner,
     );
     writeln!(
@@ -1524,12 +1562,12 @@
     begin_function_definition(out);
     writeln!(
         out,
-        "void Vec<{}>::reserve_total(::std::size_t cap) noexcept {{",
+        "void Vec<{}>::reserve_total(::std::size_t new_cap) noexcept {{",
         inner,
     );
     writeln!(
         out,
-        "  return cxxbridge1$rust_vec${}$reserve_total(this, cap);",
+        "  return cxxbridge1$rust_vec${}$reserve_total(this, new_cap);",
         instance,
     );
     writeln!(out, "}}");
@@ -1566,11 +1604,7 @@
         // know at code generation time, so we generate both C++ and Rust side
         // bindings for a "new" method anyway. But the Rust code can't be called
         // for Opaque types because the 'new' method is not implemented.
-        UniquePtr::Ident(ident) => {
-            out.types.structs.contains_key(ident)
-                || out.types.enums.contains_key(ident)
-                || out.types.aliases.contains_key(ident)
-        }
+        UniquePtr::Ident(ident) => out.types.is_maybe_trivial(ident),
         UniquePtr::CxxVector(_) => false,
     };
 
@@ -1678,9 +1712,7 @@
     // know at code generation time, so we generate both C++ and Rust side
     // bindings for a "new" method anyway. But the Rust code can't be called for
     // Opaque types because the 'new' method is not implemented.
-    let can_construct_from_value = out.types.structs.contains_key(ident)
-        || out.types.enums.contains_key(ident)
-        || out.types.aliases.contains_key(ident);
+    let can_construct_from_value = out.types.is_maybe_trivial(ident);
 
     writeln!(
         out,
@@ -1803,6 +1835,8 @@
     let instance = element.to_mangled(out.types);
 
     out.include.cstddef = true;
+    out.include.utility = true;
+    out.builtin.destroy = true;
 
     writeln!(
         out,
@@ -1811,6 +1845,7 @@
     );
     writeln!(out, "  return s.size();");
     writeln!(out, "}}");
+
     writeln!(
         out,
         "{} *cxxbridge1$std$vector${}$get_unchecked(::std::vector<{}> *s, ::std::size_t pos) noexcept {{",
@@ -1819,6 +1854,26 @@
     writeln!(out, "  return &(*s)[pos];");
     writeln!(out, "}}");
 
+    if out.types.is_maybe_trivial(element) {
+        writeln!(
+            out,
+            "void cxxbridge1$std$vector${}$push_back(::std::vector<{}> *v, {} *value) noexcept {{",
+            instance, inner, inner,
+        );
+        writeln!(out, "  v->push_back(::std::move(*value));");
+        writeln!(out, "  ::rust::destroy(value);");
+        writeln!(out, "}}");
+
+        writeln!(
+            out,
+            "void cxxbridge1$std$vector${}$pop_back(::std::vector<{}> *v, {} *out) noexcept {{",
+            instance, inner, inner,
+        );
+        writeln!(out, "  ::new (out) {}(::std::move(v->back()));", inner);
+        writeln!(out, "  v->pop_back();");
+        writeln!(out, "}}");
+    }
+
     out.include.memory = true;
     write_unique_ptr_common(out, UniquePtr::CxxVector(element));
 }
diff --git a/include/cxx.h b/include/cxx.h
index cdc63fb..dffcb01 100644
--- a/include/cxx.h
+++ b/include/cxx.h
@@ -43,6 +43,8 @@
   String(const std::string &);
   String(const char *);
   String(const char *, std::size_t);
+  String(const char16_t *);
+  String(const char16_t *, std::size_t);
 
   String &operator=(const String &) &noexcept;
   String &operator=(String &&) &noexcept;
@@ -53,9 +55,13 @@
   const char *data() const noexcept;
   std::size_t size() const noexcept;
   std::size_t length() const noexcept;
+  bool empty() const noexcept;
 
   const char *c_str() noexcept;
 
+  std::size_t capacity() const noexcept;
+  void reserve(size_t new_cap) noexcept;
+
   using iterator = char *;
   iterator begin() noexcept;
   iterator end() noexcept;
@@ -105,6 +111,7 @@
   const char *data() const noexcept;
   std::size_t size() const noexcept;
   std::size_t length() const noexcept;
+  bool empty() const noexcept;
 
   // Important in order for System V ABI to pass in registers.
   Str(const Str &) noexcept = default;
@@ -334,7 +341,7 @@
   Vec(unsafe_bitcopy_t, const Vec &) noexcept;
 
 private:
-  void reserve_total(std::size_t cap) noexcept;
+  void reserve_total(std::size_t new_cap) noexcept;
   void set_len(std::size_t len) noexcept;
   void drop() noexcept;
 
@@ -475,7 +482,7 @@
 #define CXXBRIDGE1_RUST_FN
 template <typename Ret, typename... Args>
 Ret Fn<Ret(Args...)>::operator()(Args... args) const noexcept {
-  return (*this->trampoline)(std::move(args)..., this->fn);
+  return (*this->trampoline)(std::forward<Args>(args)..., this->fn);
 }
 
 template <typename Ret, typename... Args>
@@ -536,8 +543,8 @@
 template <typename T>
 T &Slice<T>::operator[](std::size_t n) const noexcept {
   assert(n < this->size());
-  auto pos = static_cast<char *>(slicePtr(this)) + size_of<T>() * n;
-  return *reinterpret_cast<T *>(pos);
+  auto ptr = static_cast<char *>(slicePtr(this)) + size_of<T>() * n;
+  return *reinterpret_cast<T *>(ptr);
 }
 
 template <typename T>
@@ -575,8 +582,8 @@
 template <typename T>
 typename Slice<T>::iterator::reference Slice<T>::iterator::operator[](
     typename Slice<T>::iterator::difference_type n) const noexcept {
-  auto pos = static_cast<char *>(this->pos) + this->stride * n;
-  return *reinterpret_cast<T *>(pos);
+  auto ptr = static_cast<char *>(this->pos) + this->stride * n;
+  return *reinterpret_cast<T *>(ptr);
 }
 
 template <typename T>
diff --git a/macro/Cargo.toml b/macro/Cargo.toml
index a3df101..65f15c3 100644
--- a/macro/Cargo.toml
+++ b/macro/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cxxbridge-macro"
-version = "1.0.42"
+version = "1.0.54"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
@@ -14,10 +14,20 @@
 [lib]
 proc-macro = true
 
+[features]
+experimental = ["clang-ast", "flate2", "memmap", "serde", "serde_json"]
+
 [dependencies]
 proc-macro2 = "1.0"
 quote = "1.0.4"
-syn = { version = "1.0.68", features = ["full"] }
+syn = { version = "1.0.70", features = ["full"] }
+
+# optional dependencies
+clang-ast = { version = "0.1", optional = true }
+flate2 = { version = "1.0", optional = true }
+memmap = { version = "0.7", optional = true }
+serde = { version = "1.0", optional = true, features = ["derive"] }
+serde_json = { version = "1.0", optional = true }
 
 [dev-dependencies]
 cxx = { version = "1.0", path = ".." }
diff --git a/macro/src/clang.rs b/macro/src/clang.rs
new file mode 100644
index 0000000..099d5a6
--- /dev/null
+++ b/macro/src/clang.rs
@@ -0,0 +1,51 @@
+use serde::{Deserialize, Serialize};
+
+pub type Node = clang_ast::Node<Clang>;
+
+#[derive(Deserialize, Serialize)]
+pub enum Clang {
+    NamespaceDecl(NamespaceDecl),
+    EnumDecl(EnumDecl),
+    EnumConstantDecl(EnumConstantDecl),
+    ImplicitCastExpr,
+    ConstantExpr(ConstantExpr),
+    Unknown,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct NamespaceDecl {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<Box<str>>,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct EnumDecl {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<Box<str>>,
+    #[serde(
+        rename = "fixedUnderlyingType",
+        skip_serializing_if = "Option::is_none"
+    )]
+    pub fixed_underlying_type: Option<Type>,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct EnumConstantDecl {
+    pub name: Box<str>,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct ConstantExpr {
+    pub value: Box<str>,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct Type {
+    #[serde(rename = "qualType")]
+    pub qual_type: Box<str>,
+    #[serde(rename = "desugaredQualType", skip_serializing_if = "Option::is_none")]
+    pub desugared_qual_type: Option<Box<str>>,
+}
+
+#[cfg(all(test, target_pointer_width = "64"))]
+const _: [(); std::mem::size_of::<Node>()] = [(); 88];
diff --git a/macro/src/derive.rs b/macro/src/derive.rs
index 2f77095..ea36e3e 100644
--- a/macro/src/derive.rs
+++ b/macro/src/derive.rs
@@ -151,6 +151,7 @@
     let fields = strct.fields.iter().map(|field| &field.name.rust);
 
     quote_spanned! {span=>
+        #[allow(clippy::derivable_impls)] // different spans than the derived impl
         impl #generics ::std::default::Default for #ident #generics {
             fn default() -> Self {
                 #ident {
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 7c194ad..5a879cb 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -14,7 +14,7 @@
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote, quote_spanned, ToTokens};
 use std::mem;
-use syn::{parse_quote, punctuated, Lifetime, Result, Token};
+use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token};
 
 pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
     let ref mut errors = Errors::new();
@@ -32,10 +32,14 @@
     let content = mem::take(&mut ffi.content);
     let trusted = ffi.unsafety.is_some();
     let namespace = &ffi.namespace;
-    let ref apis = syntax::parse_items(errors, content, trusted, namespace);
+    let ref mut apis = syntax::parse_items(errors, content, trusted, namespace);
+    #[cfg(feature = "experimental")]
+    crate::load::load(errors, apis);
     let ref types = Types::collect(errors, apis);
     errors.propagate()?;
-    check::typecheck(errors, apis, types);
+
+    let generator = check::Generator::Macro;
+    check::typecheck(errors, apis, types, generator);
     errors.propagate()?;
 
     Ok(expand(ffi, doc, attrs, apis, types))
@@ -130,8 +134,9 @@
     quote! {
         #doc
         #attrs
-        #[deny(improper_ctypes)]
-        #[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms, clippy::unknown_clippy_lints)]
+        #[deny(improper_ctypes, improper_ctypes_definitions)]
+        #[allow(clippy::unknown_clippy_lints)]
+        #[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
         #vis #mod_token #ident #expanded
     }
 }
@@ -288,7 +293,7 @@
     let ident = &enm.name.rust;
     let doc = &enm.doc;
     let attrs = &enm.attrs;
-    let repr = enm.repr;
+    let repr = &enm.repr;
     let type_id = type_id(&enm.name);
     let variants = enm.variants.iter().map(|variant| {
         let doc = &variant.doc;
@@ -419,18 +424,19 @@
         quote!(_: #receiver_type)
     });
     let args = efn.args.iter().map(|arg| {
-        let ident = &arg.name.rust;
+        let var = &arg.name.rust;
+        let colon = arg.colon_token;
         let ty = expand_extern_type(&arg.ty, types, true);
         if arg.ty == RustString {
-            quote!(#ident: *const #ty)
+            quote!(#var #colon *const #ty)
         } else if let Type::RustVec(_) = arg.ty {
-            quote!(#ident: *const #ty)
+            quote!(#var #colon *const #ty)
         } else if let Type::Fn(_) = arg.ty {
-            quote!(#ident: ::cxx::private::FatFunction)
+            quote!(#var #colon ::cxx::private::FatFunction)
         } else if types.needs_indirect_abi(&arg.ty) {
-            quote!(#ident: *mut #ty)
+            quote!(#var #colon *mut #ty)
         } else {
-            quote!(#ident: #ty)
+            quote!(#var #colon #ty)
         }
     });
     let all_args = receiver.chain(args);
@@ -459,8 +465,9 @@
     let receiver = efn.receiver.iter().map(|receiver| {
         let var = receiver.var;
         if receiver.pinned {
+            let colon = receiver.colon_token;
             let ty = receiver.ty_self();
-            quote!(#var: #ty)
+            quote!(#var #colon #ty)
         } else {
             let ampersand = receiver.ampersand;
             let lifetime = &receiver.lifetime;
@@ -486,53 +493,66 @@
         .map(|receiver| receiver.var.to_token_stream());
     let arg_vars = efn.args.iter().map(|arg| {
         let var = &arg.name.rust;
+        let span = var.span();
         match &arg.ty {
             Type::Ident(ident) if ident.rust == RustString => {
-                quote!(#var.as_mut_ptr() as *const ::cxx::private::RustString)
+                quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustString)
             }
-            Type::RustBox(_) => quote!(::std::boxed::Box::into_raw(#var)),
-            Type::UniquePtr(_) => quote!(::cxx::UniquePtr::into_raw(#var)),
-            Type::RustVec(_) => quote!(#var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
+            Type::RustBox(ty) => {
+                if types.is_considered_improper_ctype(&ty.inner) {
+                    quote_spanned!(span=> ::std::boxed::Box::into_raw(#var).cast())
+                } else {
+                    quote_spanned!(span=> ::std::boxed::Box::into_raw(#var))
+                }
+            }
+            Type::UniquePtr(ty) => {
+                if types.is_considered_improper_ctype(&ty.inner) {
+                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var).cast())
+                } else {
+                    quote_spanned!(span=> ::cxx::UniquePtr::into_raw(#var))
+                }
+            }
+            Type::RustVec(_) => quote_spanned!(span=> #var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
-                    false => quote!(::cxx::private::RustString::from_ref(#var)),
-                    true => quote!(::cxx::private::RustString::from_mut(#var)),
+                    false => quote_spanned!(span=> ::cxx::private::RustString::from_ref(#var)),
+                    true => quote_spanned!(span=> ::cxx::private::RustString::from_mut(#var)),
                 },
                 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
-                    false => quote!(::cxx::private::RustVec::from_ref_vec_string(#var)),
-                    true => quote!(::cxx::private::RustVec::from_mut_vec_string(#var)),
+                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string(#var)),
+                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string(#var)),
                 },
                 Type::RustVec(_) => match ty.mutable {
-                    false => quote!(::cxx::private::RustVec::from_ref(#var)),
-                    true => quote!(::cxx::private::RustVec::from_mut(#var)),
+                    false => quote_spanned!(span=> ::cxx::private::RustVec::from_ref(#var)),
+                    true => quote_spanned!(span=> ::cxx::private::RustVec::from_mut(#var)),
                 },
                 inner if types.is_considered_improper_ctype(inner) => {
                     let var = match ty.pinned {
                         false => quote!(#var),
-                        true => quote!(::std::pin::Pin::into_inner_unchecked(#var)),
+                        true => quote_spanned!(span=> ::std::pin::Pin::into_inner_unchecked(#var)),
                     };
                     match ty.mutable {
                         false => {
-                            quote!(#var as *const #inner as *const ::std::ffi::c_void)
+                            quote_spanned!(span=> #var as *const #inner as *const ::std::ffi::c_void)
                         }
-                        true => quote!(#var as *mut #inner as *mut ::std::ffi::c_void),
+                        true => quote_spanned!(span=> #var as *mut #inner as *mut ::std::ffi::c_void),
                     }
                 }
                 _ => quote!(#var),
             },
             Type::Ptr(ty) => {
                 if types.is_considered_improper_ctype(&ty.inner) {
-                    quote!(#var.cast())
+                    quote_spanned!(span=> #var.cast())
                 } else {
                     quote!(#var)
                 }
             }
-            Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
+            Type::Str(_) => quote_spanned!(span=> ::cxx::private::RustStr::from(#var)),
             Type::SliceRef(ty) => match ty.mutable {
-                false => quote!(::cxx::private::RustSlice::from_ref(#var)),
-                true => quote!(::cxx::private::RustSlice::from_mut(#var)),
+                false => quote_spanned!(span=> ::cxx::private::RustSlice::from_ref(#var)),
+                true => quote_spanned!(span=> ::cxx::private::RustSlice::from_mut(#var)),
             },
-            ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
+            ty if types.needs_indirect_abi(ty) => quote_spanned!(span=> #var.as_mut_ptr()),
             _ => quote!(#var),
         }
     });
@@ -555,35 +575,37 @@
         .filter(|arg| types.needs_indirect_abi(&arg.ty))
         .map(|arg| {
             let var = &arg.name.rust;
+            let span = var.span();
             // These are arguments for which C++ has taken ownership of the data
             // behind the mut reference it received.
-            quote! {
+            quote_spanned! {span=>
                 let mut #var = ::std::mem::MaybeUninit::new(#var);
             }
         })
         .collect::<TokenStream>();
     let local_name = format_ident!("__{}", efn.name.rust);
+    let span = efn.semi_token.span;
     let call = if indirect_return {
         let ret = expand_extern_type(efn.ret.as_ref().unwrap(), types, true);
-        setup.extend(quote! {
+        setup.extend(quote_spanned! {span=>
             let mut __return = ::std::mem::MaybeUninit::<#ret>::uninit();
         });
         setup.extend(if efn.throws {
-            quote! {
+            quote_spanned! {span=>
                 #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?;
             }
         } else {
-            quote! {
+            quote_spanned! {span=>
                 #local_name(#(#vars,)* __return.as_mut_ptr());
             }
         });
-        quote!(__return.assume_init())
+        quote_spanned!(span=> __return.assume_init())
     } else if efn.throws {
-        quote! {
+        quote_spanned! {span=>
             #local_name(#(#vars),*).exception()
         }
     } else {
-        quote! {
+        quote_spanned! {span=>
             #local_name(#(#vars),*)
         }
     };
@@ -594,72 +616,88 @@
         expr = match &efn.ret {
             None => call,
             Some(ret) => match ret {
-                Type::Ident(ident) if ident.rust == RustString => quote!(#call.into_string()),
-                Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#call)),
-                Type::RustVec(vec) => {
-                    if vec.inner == RustString {
-                        quote!(#call.into_vec_string())
+                Type::Ident(ident) if ident.rust == RustString => {
+                    quote_spanned!(span=> #call.into_string())
+                }
+                Type::RustBox(ty) => {
+                    if types.is_considered_improper_ctype(&ty.inner) {
+                        quote_spanned!(span=> ::std::boxed::Box::from_raw(#call.cast()))
                     } else {
-                        quote!(#call.into_vec())
+                        quote_spanned!(span=> ::std::boxed::Box::from_raw(#call))
                     }
                 }
-                Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#call)),
+                Type::RustVec(vec) => {
+                    if vec.inner == RustString {
+                        quote_spanned!(span=> #call.into_vec_string())
+                    } else {
+                        quote_spanned!(span=> #call.into_vec())
+                    }
+                }
+                Type::UniquePtr(ty) => {
+                    if types.is_considered_improper_ctype(&ty.inner) {
+                        quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call.cast()))
+                    } else {
+                        quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call))
+                    }
+                }
                 Type::Ref(ty) => match &ty.inner {
                     Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
-                        false => quote!(#call.as_string()),
-                        true => quote!(#call.as_mut_string()),
+                        false => quote_spanned!(span=> #call.as_string()),
+                        true => quote_spanned!(span=> #call.as_mut_string()),
                     },
                     Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
-                        false => quote!(#call.as_vec_string()),
-                        true => quote!(#call.as_mut_vec_string()),
+                        false => quote_spanned!(span=> #call.as_vec_string()),
+                        true => quote_spanned!(span=> #call.as_mut_vec_string()),
                     },
                     Type::RustVec(_) => match ty.mutable {
-                        false => quote!(#call.as_vec()),
-                        true => quote!(#call.as_mut_vec()),
+                        false => quote_spanned!(span=> #call.as_vec()),
+                        true => quote_spanned!(span=> #call.as_mut_vec()),
                     },
                     inner if types.is_considered_improper_ctype(inner) => {
                         let mutability = ty.mutability;
-                        let deref_mut = quote!(&#mutability *#call.cast());
+                        let deref_mut = quote_spanned!(span=> &#mutability *#call.cast());
                         match ty.pinned {
                             false => deref_mut,
-                            true => quote!(::std::pin::Pin::new_unchecked(#deref_mut)),
+                            true => {
+                                quote_spanned!(span=> ::std::pin::Pin::new_unchecked(#deref_mut))
+                            }
                         }
                     }
                     _ => call,
                 },
                 Type::Ptr(ty) => {
                     if types.is_considered_improper_ctype(&ty.inner) {
-                        quote!(#call.cast())
+                        quote_spanned!(span=> #call.cast())
                     } else {
                         call
                     }
                 }
-                Type::Str(_) => quote!(#call.as_str()),
+                Type::Str(_) => quote_spanned!(span=> #call.as_str()),
                 Type::SliceRef(slice) => {
                     let inner = &slice.inner;
                     match slice.mutable {
-                        false => quote!(#call.as_slice::<#inner>()),
-                        true => quote!(#call.as_mut_slice::<#inner>()),
+                        false => quote_spanned!(span=> #call.as_slice::<#inner>()),
+                        true => quote_spanned!(span=> #call.as_mut_slice::<#inner>()),
                     }
                 }
                 _ => call,
             },
         };
         if efn.throws {
-            expr = quote!(::std::result::Result::Ok(#expr));
+            expr = quote_spanned!(span=> ::std::result::Result::Ok(#expr));
         }
     };
     let mut dispatch = quote!(#setup #expr);
     let visibility = efn.visibility;
     let unsafety = &efn.sig.unsafety;
     if unsafety.is_none() {
-        dispatch = quote!(unsafe { #dispatch });
+        dispatch = quote_spanned!(span=> unsafe { #dispatch });
     }
     let fn_token = efn.sig.fn_token;
     let ident = &efn.name.rust;
     let generics = &efn.generics;
     let arg_list = quote_spanned!(efn.sig.paren_token.span=> (#(#all_args,)*));
-    let fn_body = quote_spanned!(efn.semi_token.span=> {
+    let fn_body = quote_spanned!(span=> {
         extern "C" {
             #decl
         }
@@ -697,7 +735,7 @@
                 };
                 &elided_generics
             };
-            quote! {
+            quote_spanned! {ident.span()=>
                 impl #generics #receiver_ident #receiver_generics {
                     #doc
                     #attrs
@@ -718,6 +756,7 @@
     let r_trampoline = mangle::r_trampoline(efn, var, types);
     let local_name = parse_quote!(__);
     let catch_unwind_label = format!("::{}::{}", efn.name.rust, var.rust);
+    let body_span = efn.semi_token.span;
     let shim = expand_rust_function_shim_impl(
         sig,
         types,
@@ -725,6 +764,8 @@
         local_name,
         catch_unwind_label,
         None,
+        Some(&efn.generics),
+        body_span,
     );
     let var = &var.rust;
 
@@ -736,9 +777,9 @@
                     fn trampoline();
                 }
                 #shim
-                trampoline as usize as *const ()
+                trampoline as usize as *const ::std::ffi::c_void
             },
-            ptr: #var as usize as *const (),
+            ptr: #var as usize as *const ::std::ffi::c_void,
         };
     }
 }
@@ -857,6 +898,7 @@
         Some(receiver) => format!("::{}::{}", receiver.ty.rust, efn.name.rust),
     };
     let invoke = Some(&efn.name.rust);
+    let body_span = efn.semi_token.span;
     expand_rust_function_shim_impl(
         efn,
         types,
@@ -864,6 +906,8 @@
         local_name,
         catch_unwind_label,
         invoke,
+        None,
+        body_span,
     )
 }
 
@@ -874,138 +918,166 @@
     local_name: Ident,
     catch_unwind_label: String,
     invoke: Option<&Ident>,
+    outer_generics: Option<&Generics>,
+    body_span: Span,
 ) -> TokenStream {
-    let generics = &sig.generics;
+    let generics = outer_generics.unwrap_or(&sig.generics);
     let receiver_var = sig
         .receiver
         .as_ref()
         .map(|receiver| quote_spanned!(receiver.var.span=> __self));
     let receiver = sig.receiver.as_ref().map(|receiver| {
+        let colon = receiver.colon_token;
         let receiver_type = receiver.ty();
-        quote!(#receiver_var: #receiver_type)
+        quote!(#receiver_var #colon #receiver_type)
     });
     let args = sig.args.iter().map(|arg| {
-        let ident = &arg.name.rust;
+        let var = &arg.name.rust;
+        let colon = arg.colon_token;
         let ty = expand_extern_type(&arg.ty, types, false);
         if types.needs_indirect_abi(&arg.ty) {
-            quote!(#ident: *mut #ty)
+            quote!(#var #colon *mut #ty)
         } else {
-            quote!(#ident: #ty)
+            quote!(#var #colon #ty)
         }
     });
     let all_args = receiver.into_iter().chain(args);
 
     let arg_vars = sig.args.iter().map(|arg| {
-        let ident = &arg.name.rust;
+        let var = &arg.name.rust;
+        let span = var.span();
         match &arg.ty {
             Type::Ident(i) if i.rust == RustString => {
-                quote!(::std::mem::take((*#ident).as_mut_string()))
+                quote_spanned!(span=> ::std::mem::take((*#var).as_mut_string()))
             }
-            Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#ident)),
+            Type::RustBox(_) => quote_spanned!(span=> ::std::boxed::Box::from_raw(#var)),
             Type::RustVec(vec) => {
                 if vec.inner == RustString {
-                    quote!(::std::mem::take((*#ident).as_mut_vec_string()))
+                    quote_spanned!(span=> ::std::mem::take((*#var).as_mut_vec_string()))
                 } else {
-                    quote!(::std::mem::take((*#ident).as_mut_vec()))
+                    quote_spanned!(span=> ::std::mem::take((*#var).as_mut_vec()))
                 }
             }
-            Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#ident)),
+            Type::UniquePtr(_) => quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#var)),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(i) if i.rust == RustString => match ty.mutable {
-                    false => quote!(#ident.as_string()),
-                    true => quote!(#ident.as_mut_string()),
+                    false => quote_spanned!(span=> #var.as_string()),
+                    true => quote_spanned!(span=> #var.as_mut_string()),
                 },
                 Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
-                    false => quote!(#ident.as_vec_string()),
-                    true => quote!(#ident.as_mut_vec_string()),
+                    false => quote_spanned!(span=> #var.as_vec_string()),
+                    true => quote_spanned!(span=> #var.as_mut_vec_string()),
                 },
                 Type::RustVec(_) => match ty.mutable {
-                    false => quote!(#ident.as_vec()),
-                    true => quote!(#ident.as_mut_vec()),
+                    false => quote_spanned!(span=> #var.as_vec()),
+                    true => quote_spanned!(span=> #var.as_mut_vec()),
                 },
-                _ => quote!(#ident),
+                _ => quote!(#var),
             },
-            Type::Str(_) => quote!(#ident.as_str()),
+            Type::Str(_) => quote_spanned!(span=> #var.as_str()),
             Type::SliceRef(slice) => {
                 let inner = &slice.inner;
                 match slice.mutable {
-                    false => quote!(#ident.as_slice::<#inner>()),
-                    true => quote!(#ident.as_mut_slice::<#inner>()),
+                    false => quote_spanned!(span=> #var.as_slice::<#inner>()),
+                    true => quote_spanned!(span=> #var.as_mut_slice::<#inner>()),
                 }
             }
-            ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
-            _ => quote!(#ident),
+            ty if types.needs_indirect_abi(ty) => quote_spanned!(span=> ::std::ptr::read(#var)),
+            _ => quote!(#var),
         }
     });
-    let vars = receiver_var.into_iter().chain(arg_vars);
+    let vars: Vec<_> = receiver_var.into_iter().chain(arg_vars).collect();
 
     let wrap_super = invoke.map(|invoke| expand_rust_function_shim_super(sig, &local_name, invoke));
 
+    let mut requires_closure;
     let mut call = match invoke {
-        Some(_) => quote!(#local_name),
-        None => quote!(::std::mem::transmute::<*const (), #sig>(__extern)),
+        Some(_) => {
+            requires_closure = false;
+            quote!(#local_name)
+        }
+        None => {
+            requires_closure = true;
+            quote!(::std::mem::transmute::<*const (), #sig>(__extern))
+        }
     };
+    requires_closure |= !vars.is_empty();
     call.extend(quote! { (#(#vars),*) });
 
+    let span = body_span;
     let conversion = sig.ret.as_ref().and_then(|ret| match ret {
         Type::Ident(ident) if ident.rust == RustString => {
-            Some(quote!(::cxx::private::RustString::from))
+            Some(quote_spanned!(span=> ::cxx::private::RustString::from))
         }
-        Type::RustBox(_) => Some(quote!(::std::boxed::Box::into_raw)),
+        Type::RustBox(_) => Some(quote_spanned!(span=> ::std::boxed::Box::into_raw)),
         Type::RustVec(vec) => {
             if vec.inner == RustString {
-                Some(quote!(::cxx::private::RustVec::from_vec_string))
+                Some(quote_spanned!(span=> ::cxx::private::RustVec::from_vec_string))
             } else {
-                Some(quote!(::cxx::private::RustVec::from))
+                Some(quote_spanned!(span=> ::cxx::private::RustVec::from))
             }
         }
-        Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::into_raw)),
+        Type::UniquePtr(_) => Some(quote_spanned!(span=> ::cxx::UniquePtr::into_raw)),
         Type::Ref(ty) => match &ty.inner {
             Type::Ident(ident) if ident.rust == RustString => match ty.mutable {
-                false => Some(quote!(::cxx::private::RustString::from_ref)),
-                true => Some(quote!(::cxx::private::RustString::from_mut)),
+                false => Some(quote_spanned!(span=> ::cxx::private::RustString::from_ref)),
+                true => Some(quote_spanned!(span=> ::cxx::private::RustString::from_mut)),
             },
             Type::RustVec(vec) if vec.inner == RustString => match ty.mutable {
-                false => Some(quote!(::cxx::private::RustVec::from_ref_vec_string)),
-                true => Some(quote!(::cxx::private::RustVec::from_mut_vec_string)),
+                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref_vec_string)),
+                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut_vec_string)),
             },
             Type::RustVec(_) => match ty.mutable {
-                false => Some(quote!(::cxx::private::RustVec::from_ref)),
-                true => Some(quote!(::cxx::private::RustVec::from_mut)),
+                false => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_ref)),
+                true => Some(quote_spanned!(span=> ::cxx::private::RustVec::from_mut)),
             },
             _ => None,
         },
-        Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
+        Type::Str(_) => Some(quote_spanned!(span=> ::cxx::private::RustStr::from)),
         Type::SliceRef(ty) => match ty.mutable {
-            false => Some(quote!(::cxx::private::RustSlice::from_ref)),
-            true => Some(quote!(::cxx::private::RustSlice::from_mut)),
+            false => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_ref)),
+            true => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_mut)),
         },
         _ => None,
     });
 
     let mut expr = match conversion {
         None => call,
-        Some(conversion) if !sig.throws => quote!(#conversion(#call)),
-        Some(conversion) => quote!(::std::result::Result::map(#call, #conversion)),
+        Some(conversion) if !sig.throws => {
+            requires_closure = true;
+            quote_spanned!(span=> #conversion(#call))
+        }
+        Some(conversion) => {
+            requires_closure = true;
+            quote_spanned!(span=> ::std::result::Result::map(#call, #conversion))
+        }
     };
 
     let mut outparam = None;
     let indirect_return = indirect_return(sig, types);
     if indirect_return {
         let ret = expand_extern_type(sig.ret.as_ref().unwrap(), types, false);
-        outparam = Some(quote!(__return: *mut #ret,));
+        outparam = Some(quote_spanned!(span=> __return: *mut #ret,));
     }
     if sig.throws {
         let out = match sig.ret {
-            Some(_) => quote!(__return),
-            None => quote!(&mut ()),
+            Some(_) => quote_spanned!(span=> __return),
+            None => quote_spanned!(span=> &mut ()),
         };
-        expr = quote!(::cxx::private::r#try(#out, #expr));
+        requires_closure = true;
+        expr = quote_spanned!(span=> ::cxx::private::r#try(#out, #expr));
     } else if indirect_return {
-        expr = quote!(::std::ptr::write(__return, #expr));
+        requires_closure = true;
+        expr = quote_spanned!(span=> ::std::ptr::write(__return, #expr));
     }
 
-    expr = quote!(::cxx::private::catch_unwind(__fn, move || #expr));
+    let closure = if requires_closure {
+        quote_spanned!(span=> move || #expr)
+    } else {
+        quote!(#local_name)
+    };
+
+    expr = quote_spanned!(span=> ::cxx::private::catch_unwind(__fn, #closure));
 
     let ret = if sig.throws {
         quote!(-> ::cxx::private::Result)
@@ -1014,11 +1086,11 @@
     };
 
     let pointer = match invoke {
-        None => Some(quote!(__extern: *const ())),
+        None => Some(quote_spanned!(span=> __extern: *const ())),
         Some(_) => None,
     };
 
-    quote! {
+    quote_spanned! {span=>
         #[doc(hidden)]
         #[export_name = #link_name]
         unsafe extern "C" fn #local_name #generics(#(#all_args,)* #outparam #pointer) #ret {
@@ -1055,9 +1127,11 @@
             Some(ret) => quote!(#ret),
             None => quote!(()),
         };
-        let impl_trait = quote_spanned!(result.span=> impl);
-        let display = quote_spanned!(rangle.span=> ::std::fmt::Display);
-        quote!(-> ::std::result::Result<#ok, #impl_trait #display>)
+        // Set spans that result in the `Result<...>` written by the user being
+        // highlighted as the cause if their error type has no Display impl.
+        let result_begin = quote_spanned!(result.span=> ::std::result::Result<#ok, impl);
+        let result_end = quote_spanned!(rangle.span=> ::std::fmt::Display>);
+        quote!(-> #result_begin #result_end)
     } else {
         expand_return_type(&sig.ret)
     };
@@ -1227,8 +1301,8 @@
         }
         #[doc(hidden)]
         #[export_name = #link_reserve_total]
-        unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, cap: usize) {
-            (*this).reserve_total(cap);
+        unsafe extern "C" fn #local_reserve_total #impl_generics(this: *mut ::cxx::private::RustVec<#elem #ty_generics>, new_cap: usize) {
+            (*this).reserve_total(new_cap);
         }
         #[doc(hidden)]
         #[export_name = #link_set_len]
@@ -1256,18 +1330,16 @@
 
     let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
 
-    let can_construct_from_value = types.structs.contains_key(ident)
-        || types.enums.contains_key(ident)
-        || types.aliases.contains_key(ident);
+    let can_construct_from_value = types.is_maybe_trivial(ident);
     let new_method = if can_construct_from_value {
         Some(quote! {
             #[doc(hidden)]
-            fn __new(value: Self) -> *mut ::std::ffi::c_void {
+            fn __new(value: Self) -> ::std::mem::MaybeUninit<*mut ::std::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_uninit]
-                    fn __uninit(this: *mut *mut ::std::ffi::c_void) -> *mut ::std::ffi::c_void;
+                    fn __uninit(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *mut ::std::ffi::c_void;
                 }
-                let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
+                let mut repr = ::std::mem::MaybeUninit::uninit();
                 unsafe { __uninit(&mut repr).cast::<#ident #ty_generics>().write(value) }
                 repr
             }
@@ -1287,47 +1359,47 @@
                 f.write_str(#name)
             }
             #[doc(hidden)]
-            fn __null() -> *mut ::std::ffi::c_void {
+            fn __null() -> ::std::mem::MaybeUninit<*mut ::std::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_null]
-                    fn __null(this: *mut *mut ::std::ffi::c_void);
+                    fn __null(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>);
                 }
-                let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
+                let mut repr = ::std::mem::MaybeUninit::uninit();
                 unsafe { __null(&mut repr) }
                 repr
             }
             #new_method
             #[doc(hidden)]
-            unsafe fn __raw(raw: *mut Self) -> *mut ::std::ffi::c_void {
+            unsafe fn __raw(raw: *mut Self) -> ::std::mem::MaybeUninit<*mut ::std::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_raw]
-                    fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut ::std::ffi::c_void);
+                    fn __raw(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>, raw: *mut ::std::ffi::c_void);
                 }
-                let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
+                let mut repr = ::std::mem::MaybeUninit::uninit();
                 __raw(&mut repr, raw.cast());
                 repr
             }
             #[doc(hidden)]
-            unsafe fn __get(repr: *mut ::std::ffi::c_void) -> *const Self {
+            unsafe fn __get(repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *const Self {
                 extern "C" {
                     #[link_name = #link_get]
-                    fn __get(this: *const *mut ::std::ffi::c_void) -> *const ::std::ffi::c_void;
+                    fn __get(this: *const ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *const ::std::ffi::c_void;
                 }
                 __get(&repr).cast()
             }
             #[doc(hidden)]
-            unsafe fn __release(mut repr: *mut ::std::ffi::c_void) -> *mut Self {
+            unsafe fn __release(mut repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *mut Self {
                 extern "C" {
                     #[link_name = #link_release]
-                    fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut ::std::ffi::c_void;
+                    fn __release(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *mut ::std::ffi::c_void;
                 }
                 __release(&mut repr).cast()
             }
             #[doc(hidden)]
-            unsafe fn __drop(mut repr: *mut ::std::ffi::c_void) {
+            unsafe fn __drop(mut repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) {
                 extern "C" {
                     #[link_name = #link_drop]
-                    fn __drop(this: *mut *mut ::std::ffi::c_void);
+                    fn __drop(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>);
                 }
                 __drop(&mut repr);
             }
@@ -1352,9 +1424,7 @@
 
     let (impl_generics, ty_generics) = generics::split_for_impl(key, explicit_impl, resolve);
 
-    let can_construct_from_value = types.structs.contains_key(ident)
-        || types.enums.contains_key(ident)
-        || types.aliases.contains_key(ident);
+    let can_construct_from_value = types.is_maybe_trivial(ident);
     let new_method = if can_construct_from_value {
         Some(quote! {
             #[doc(hidden)]
@@ -1495,6 +1565,8 @@
     let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
     let link_size = format!("{}size", prefix);
     let link_get_unchecked = format!("{}get_unchecked", prefix);
+    let link_push_back = format!("{}push_back", prefix);
+    let link_pop_back = format!("{}pop_back", prefix);
     let unique_ptr_prefix = format!(
         "cxxbridge1$unique_ptr$std$vector${}$",
         resolve.name.to_symbol(),
@@ -1511,6 +1583,42 @@
     let end_span = explicit_impl.map_or(key.end_span, |explicit| explicit.brace_token.span);
     let unsafe_token = format_ident!("unsafe", span = begin_span);
 
+    let can_pass_element_by_value = types.is_maybe_trivial(elem);
+    let by_value_methods = if can_pass_element_by_value {
+        Some(quote_spanned! {end_span=>
+            #[doc(hidden)]
+            unsafe fn __push_back(
+                this: ::std::pin::Pin<&mut ::cxx::CxxVector<Self>>,
+                value: &mut ::std::mem::ManuallyDrop<Self>,
+            ) {
+                extern "C" {
+                    #[link_name = #link_push_back]
+                    fn __push_back #impl_generics(
+                        this: ::std::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
+                        value: *mut ::std::ffi::c_void,
+                    );
+                }
+                __push_back(this, value as *mut ::std::mem::ManuallyDrop<Self> as *mut ::std::ffi::c_void);
+            }
+            #[doc(hidden)]
+            unsafe fn __pop_back(
+                this: ::std::pin::Pin<&mut ::cxx::CxxVector<Self>>,
+                out: &mut ::std::mem::MaybeUninit<Self>,
+            ) {
+                extern "C" {
+                    #[link_name = #link_pop_back]
+                    fn __pop_back #impl_generics(
+                        this: ::std::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
+                        out: *mut ::std::ffi::c_void,
+                    );
+                }
+                __pop_back(this, out as *mut ::std::mem::MaybeUninit<Self> as *mut ::std::ffi::c_void);
+            }
+        })
+    } else {
+        None
+    };
+
     quote_spanned! {end_span=>
         #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
             #[doc(hidden)]
@@ -1529,51 +1637,55 @@
             unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
                 extern "C" {
                     #[link_name = #link_get_unchecked]
-                    fn __get_unchecked #impl_generics(_: *mut ::cxx::CxxVector<#elem #ty_generics>, _: usize) -> *mut #elem #ty_generics;
+                    fn __get_unchecked #impl_generics(
+                        v: *mut ::cxx::CxxVector<#elem #ty_generics>,
+                        pos: usize,
+                    ) -> *mut ::std::ffi::c_void;
                 }
-                __get_unchecked(v, pos)
+                __get_unchecked(v, pos) as *mut Self
             }
+            #by_value_methods
             #[doc(hidden)]
-            fn __unique_ptr_null() -> *mut ::std::ffi::c_void {
+            fn __unique_ptr_null() -> ::std::mem::MaybeUninit<*mut ::std::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_unique_ptr_null]
-                    fn __unique_ptr_null(this: *mut *mut ::std::ffi::c_void);
+                    fn __unique_ptr_null(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>);
                 }
-                let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
+                let mut repr = ::std::mem::MaybeUninit::uninit();
                 unsafe { __unique_ptr_null(&mut repr) }
                 repr
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> *mut ::std::ffi::c_void {
+            unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::std::mem::MaybeUninit<*mut ::std::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_unique_ptr_raw]
-                    fn __unique_ptr_raw #impl_generics(this: *mut *mut ::std::ffi::c_void, raw: *mut ::cxx::CxxVector<#elem #ty_generics>);
+                    fn __unique_ptr_raw #impl_generics(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>, raw: *mut ::cxx::CxxVector<#elem #ty_generics>);
                 }
-                let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
+                let mut repr = ::std::mem::MaybeUninit::uninit();
                 __unique_ptr_raw(&mut repr, raw);
                 repr
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_get(repr: *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<Self> {
+            unsafe fn __unique_ptr_get(repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *const ::cxx::CxxVector<Self> {
                 extern "C" {
                     #[link_name = #link_unique_ptr_get]
-                    fn __unique_ptr_get #impl_generics(this: *const *mut ::std::ffi::c_void) -> *const ::cxx::CxxVector<#elem #ty_generics>;
+                    fn __unique_ptr_get #impl_generics(this: *const ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *const ::cxx::CxxVector<#elem #ty_generics>;
                 }
                 __unique_ptr_get(&repr)
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_release(mut repr: *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<Self> {
+            unsafe fn __unique_ptr_release(mut repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *mut ::cxx::CxxVector<Self> {
                 extern "C" {
                     #[link_name = #link_unique_ptr_release]
-                    fn __unique_ptr_release #impl_generics(this: *mut *mut ::std::ffi::c_void) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
+                    fn __unique_ptr_release #impl_generics(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) -> *mut ::cxx::CxxVector<#elem #ty_generics>;
                 }
                 __unique_ptr_release(&mut repr)
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_drop(mut repr: *mut ::std::ffi::c_void) {
+            unsafe fn __unique_ptr_drop(mut repr: ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>) {
                 extern "C" {
                     #[link_name = #link_unique_ptr_drop]
-                    fn __unique_ptr_drop(this: *mut *mut ::std::ffi::c_void);
+                    fn __unique_ptr_drop(this: *mut ::std::mem::MaybeUninit<*mut ::std::ffi::c_void>);
                 }
                 __unique_ptr_drop(&mut repr);
             }
@@ -1596,43 +1708,72 @@
 
 fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
     match ty {
-        Type::Ident(ident) if ident.rust == RustString => quote!(::cxx::private::RustString),
+        Type::Ident(ident) if ident.rust == RustString => {
+            let span = ident.rust.span();
+            quote_spanned!(span=> ::cxx::private::RustString)
+        }
         Type::RustBox(ty) | Type::UniquePtr(ty) => {
-            let inner = expand_extern_type(&ty.inner, types, proper);
-            quote!(*mut #inner)
+            let span = ty.name.span();
+            if proper && types.is_considered_improper_ctype(&ty.inner) {
+                quote_spanned!(span=> *mut ::std::ffi::c_void)
+            } else {
+                let inner = expand_extern_type(&ty.inner, types, proper);
+                quote_spanned!(span=> *mut #inner)
+            }
         }
         Type::RustVec(ty) => {
+            let span = ty.name.span();
+            let langle = ty.langle;
             let elem = expand_extern_type(&ty.inner, types, proper);
-            quote!(::cxx::private::RustVec<#elem>)
+            let rangle = ty.rangle;
+            quote_spanned!(span=> ::cxx::private::RustVec #langle #elem #rangle)
         }
         Type::Ref(ty) => {
+            let ampersand = ty.ampersand;
+            let lifetime = &ty.lifetime;
             let mutability = ty.mutability;
             match &ty.inner {
                 Type::Ident(ident) if ident.rust == RustString => {
-                    quote!(&#mutability ::cxx::private::RustString)
+                    let span = ident.rust.span();
+                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustString)
                 }
                 Type::RustVec(ty) => {
+                    let span = ty.name.span();
+                    let langle = ty.langle;
                     let inner = expand_extern_type(&ty.inner, types, proper);
-                    quote!(&#mutability ::cxx::private::RustVec<#inner>)
+                    let rangle = ty.rangle;
+                    quote_spanned!(span=> #ampersand #lifetime #mutability ::cxx::private::RustVec #langle #inner #rangle)
                 }
-                inner if proper && types.is_considered_improper_ctype(inner) => match ty.mutable {
-                    false => quote!(*const ::std::ffi::c_void),
-                    true => quote!(*#mutability ::std::ffi::c_void),
-                },
+                inner if proper && types.is_considered_improper_ctype(inner) => {
+                    let star = Token![*](ampersand.span);
+                    match ty.mutable {
+                        false => quote!(#star const ::std::ffi::c_void),
+                        true => quote!(#star #mutability ::std::ffi::c_void),
+                    }
+                }
                 _ => quote!(#ty),
             }
         }
         Type::Ptr(ty) => {
             if proper && types.is_considered_improper_ctype(&ty.inner) {
+                let star = ty.star;
                 let mutability = ty.mutability;
                 let constness = ty.constness;
-                quote!(*#mutability #constness ::std::ffi::c_void)
+                quote!(#star #mutability #constness ::std::ffi::c_void)
             } else {
                 quote!(#ty)
             }
         }
-        Type::Str(_) => quote!(::cxx::private::RustStr),
-        Type::SliceRef(_) => quote!(::cxx::private::RustSlice),
+        Type::Str(ty) => {
+            let span = ty.ampersand.span;
+            let rust_str = Ident::new("RustStr", syn::spanned::Spanned::span(&ty.inner));
+            quote_spanned!(span=> ::cxx::private::#rust_str)
+        }
+        Type::SliceRef(ty) => {
+            let span = ty.ampersand.span;
+            let rust_slice = Ident::new("RustSlice", ty.bracket.span);
+            quote_spanned!(span=> ::cxx::private::#rust_slice)
+        }
         _ => quote!(#ty),
     }
 }
diff --git a/macro/src/lib.rs b/macro/src/lib.rs
index f8e7903..324881d 100644
--- a/macro/src/lib.rs
+++ b/macro/src/lib.rs
@@ -3,7 +3,7 @@
     clippy::default_trait_access,
     clippy::doc_markdown,
     clippy::enum_glob_use,
-    clippy::filter_map,
+    clippy::if_same_then_else,
     clippy::inherent_to_string,
     clippy::items_after_statements,
     clippy::large_enum_variant,
@@ -36,6 +36,11 @@
 mod syntax;
 mod type_id;
 
+#[cfg(feature = "experimental")]
+mod clang;
+#[cfg(feature = "experimental")]
+mod load;
+
 use crate::syntax::file::Module;
 use crate::syntax::namespace::Namespace;
 use crate::syntax::qualified::QualifiedName;
diff --git a/macro/src/load.rs b/macro/src/load.rs
new file mode 100644
index 0000000..d769ebf
--- /dev/null
+++ b/macro/src/load.rs
@@ -0,0 +1,315 @@
+use crate::clang::{Clang, Node};
+use crate::syntax::attrs::OtherAttrs;
+use crate::syntax::namespace::Namespace;
+use crate::syntax::report::Errors;
+use crate::syntax::{Api, Discriminant, Doc, Enum, EnumRepr, ForeignName, Pair, Variant};
+use flate2::write::GzDecoder;
+use memmap::Mmap;
+use proc_macro2::{Delimiter, Group, Ident, TokenStream};
+use quote::{format_ident, quote, quote_spanned};
+use std::env;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+use std::str::FromStr;
+use syn::{parse_quote, Path};
+
+const CXX_CLANG_AST: &str = "CXX_CLANG_AST";
+
+pub fn load(cx: &mut Errors, apis: &mut [Api]) {
+    let ref mut variants_from_header = Vec::new();
+    for api in apis {
+        if let Api::Enum(enm) = api {
+            if enm.variants_from_header {
+                if enm.variants.is_empty() {
+                    variants_from_header.push(enm);
+                } else {
+                    let span = span_for_enum_error(enm);
+                    cx.error(
+                        span,
+                        "enum with #![variants_from_header] must be written with no explicit variants",
+                    );
+                }
+            }
+        }
+    }
+
+    let span = match variants_from_header.get(0) {
+        None => return,
+        Some(enm) => enm.variants_from_header_attr.clone().unwrap(),
+    };
+
+    let ast_dump_path = match env::var_os(CXX_CLANG_AST) {
+        Some(ast_dump_path) => PathBuf::from(ast_dump_path),
+        None => {
+            let msg = format!(
+                "environment variable ${} has not been provided",
+                CXX_CLANG_AST,
+            );
+            return cx.error(span, msg);
+        }
+    };
+
+    let memmap = File::open(&ast_dump_path).and_then(|file| unsafe { Mmap::map(&file) });
+    let mut gunzipped;
+    let ast_dump_bytes = match match memmap {
+        Ok(ref memmap) => {
+            let is_gzipped = memmap.get(..2) == Some(b"\x1f\x8b");
+            if is_gzipped {
+                gunzipped = Vec::new();
+                let decode_result = GzDecoder::new(&mut gunzipped).write_all(&memmap);
+                decode_result.map(|_| gunzipped.as_slice())
+            } else {
+                Ok(&memmap as &[u8])
+            }
+        }
+        Err(error) => Err(error),
+    } {
+        Ok(bytes) => bytes,
+        Err(error) => {
+            let msg = format!("failed to read {}: {}", ast_dump_path.display(), error);
+            return cx.error(span, msg);
+        }
+    };
+
+    let ref root: Node = match serde_json::from_slice(ast_dump_bytes) {
+        Ok(root) => root,
+        Err(error) => {
+            let msg = format!("failed to read {}: {}", ast_dump_path.display(), error);
+            return cx.error(span, msg);
+        }
+    };
+
+    let ref mut namespace = Vec::new();
+    traverse(cx, root, namespace, variants_from_header, None);
+
+    for enm in variants_from_header {
+        if enm.variants.is_empty() {
+            let span = &enm.variants_from_header_attr;
+            let name = CxxName(&enm.name);
+            let msg = format!("failed to find any C++ definition of enum {}", name);
+            cx.error(span, msg);
+        }
+    }
+}
+
+fn traverse<'a>(
+    cx: &mut Errors,
+    node: &'a Node,
+    namespace: &mut Vec<&'a str>,
+    variants_from_header: &mut [&mut Enum],
+    mut idx: Option<usize>,
+) {
+    match &node.kind {
+        Clang::NamespaceDecl(decl) => {
+            let name = match &decl.name {
+                Some(name) => name,
+                // Can ignore enums inside an anonymous namespace.
+                None => return,
+            };
+            namespace.push(name);
+            idx = None;
+        }
+        Clang::EnumDecl(decl) => {
+            let name = match &decl.name {
+                Some(name) => name,
+                None => return,
+            };
+            idx = None;
+            for (i, enm) in variants_from_header.iter_mut().enumerate() {
+                if enm.name.cxx == **name && enm.name.namespace.iter().eq(&*namespace) {
+                    if !enm.variants.is_empty() {
+                        let span = &enm.variants_from_header_attr;
+                        let qual_name = CxxName(&enm.name);
+                        let msg = format!("found multiple C++ definitions of enum {}", qual_name);
+                        cx.error(span, msg);
+                        return;
+                    }
+                    let fixed_underlying_type = match &decl.fixed_underlying_type {
+                        Some(fixed_underlying_type) => fixed_underlying_type,
+                        None => {
+                            let span = &enm.variants_from_header_attr;
+                            let name = &enm.name.cxx;
+                            let qual_name = CxxName(&enm.name);
+                            let msg = format!(
+                                "implicit implementation-defined repr for enum {} is not supported yet; consider changing its C++ definition to `enum {}: int {{...}}",
+                                qual_name, name,
+                            );
+                            cx.error(span, msg);
+                            return;
+                        }
+                    };
+                    let repr = translate_qual_type(
+                        cx,
+                        &enm,
+                        fixed_underlying_type
+                            .desugared_qual_type
+                            .as_ref()
+                            .unwrap_or(&fixed_underlying_type.qual_type),
+                    );
+                    enm.repr = EnumRepr::Foreign { rust_type: repr };
+                    idx = Some(i);
+                    break;
+                }
+            }
+            if idx.is_none() {
+                return;
+            }
+        }
+        Clang::EnumConstantDecl(decl) => {
+            if let Some(idx) = idx {
+                let enm = &mut *variants_from_header[idx];
+                let span = enm
+                    .variants_from_header_attr
+                    .as_ref()
+                    .unwrap()
+                    .path
+                    .get_ident()
+                    .unwrap()
+                    .span();
+                let cxx_name = match ForeignName::parse(&decl.name, span) {
+                    Ok(foreign_name) => foreign_name,
+                    Err(_) => {
+                        let span = &enm.variants_from_header_attr;
+                        let msg = format!("unsupported C++ variant name: {}", decl.name);
+                        return cx.error(span, msg);
+                    }
+                };
+                let rust_name: Ident = match syn::parse_str(&decl.name) {
+                    Ok(ident) => ident,
+                    Err(_) => format_ident!("__Variant{}", enm.variants.len()),
+                };
+                let discriminant = match discriminant_value(&node.inner) {
+                    ParsedDiscriminant::Constant(discriminant) => discriminant,
+                    ParsedDiscriminant::Successor => match enm.variants.last() {
+                        None => Discriminant::zero(),
+                        Some(last) => match last.discriminant.checked_succ() {
+                            Some(discriminant) => discriminant,
+                            None => {
+                                let span = &enm.variants_from_header_attr;
+                                let msg = format!(
+                                    "overflow processing discriminant value for variant: {}",
+                                    decl.name,
+                                );
+                                return cx.error(span, msg);
+                            }
+                        },
+                    },
+                    ParsedDiscriminant::Fail => {
+                        let span = &enm.variants_from_header_attr;
+                        let msg = format!(
+                            "failed to obtain discriminant value for variant: {}",
+                            decl.name,
+                        );
+                        cx.error(span, msg);
+                        Discriminant::zero()
+                    }
+                };
+                enm.variants.push(Variant {
+                    doc: Doc::new(),
+                    attrs: OtherAttrs::none(),
+                    name: Pair {
+                        namespace: Namespace::ROOT,
+                        cxx: cxx_name,
+                        rust: rust_name,
+                    },
+                    discriminant,
+                    expr: None,
+                });
+            }
+        }
+        _ => {}
+    }
+    for inner in &node.inner {
+        traverse(cx, inner, namespace, variants_from_header, idx);
+    }
+    if let Clang::NamespaceDecl(_) = &node.kind {
+        let _ = namespace.pop().unwrap();
+    }
+}
+
+fn translate_qual_type(cx: &mut Errors, enm: &Enum, qual_type: &str) -> Path {
+    let rust_std_name = match qual_type {
+        "char" => "c_char",
+        "int" => "c_int",
+        "long" => "c_long",
+        "long long" => "c_longlong",
+        "signed char" => "c_schar",
+        "short" => "c_short",
+        "unsigned char" => "c_uchar",
+        "unsigned int" => "c_uint",
+        "unsigned long" => "c_ulong",
+        "unsigned long long" => "c_ulonglong",
+        "unsigned short" => "c_ushort",
+        unsupported => {
+            let span = &enm.variants_from_header_attr;
+            let qual_name = CxxName(&enm.name);
+            let msg = format!(
+                "unsupported underlying type for {}: {}",
+                qual_name, unsupported,
+            );
+            cx.error(span, msg);
+            "c_int"
+        }
+    };
+    let span = enm
+        .variants_from_header_attr
+        .as_ref()
+        .unwrap()
+        .path
+        .get_ident()
+        .unwrap()
+        .span();
+    let ident = Ident::new(rust_std_name, span);
+    let path = quote_spanned!(span=> ::std::os::raw::#ident);
+    parse_quote!(#path)
+}
+
+enum ParsedDiscriminant {
+    Constant(Discriminant),
+    Successor,
+    Fail,
+}
+
+fn discriminant_value(mut clang: &[Node]) -> ParsedDiscriminant {
+    if clang.is_empty() {
+        // No discriminant expression provided; use successor of previous
+        // descriminant.
+        return ParsedDiscriminant::Successor;
+    }
+
+    loop {
+        if clang.len() != 1 {
+            return ParsedDiscriminant::Fail;
+        }
+
+        let node = &clang[0];
+        match &node.kind {
+            Clang::ImplicitCastExpr => clang = &node.inner,
+            Clang::ConstantExpr(expr) => match Discriminant::from_str(&expr.value) {
+                Ok(discriminant) => return ParsedDiscriminant::Constant(discriminant),
+                Err(_) => return ParsedDiscriminant::Fail,
+            },
+            _ => return ParsedDiscriminant::Fail,
+        }
+    }
+}
+
+fn span_for_enum_error(enm: &Enum) -> TokenStream {
+    let enum_token = enm.enum_token;
+    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
+    brace_token.set_span(enm.brace_token.span);
+    quote!(#enum_token #brace_token)
+}
+
+struct CxxName<'a>(&'a Pair);
+
+impl<'a> Display for CxxName<'a> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        for namespace in &self.0.namespace {
+            write!(formatter, "{}::", namespace)?;
+        }
+        write!(formatter, "{}", self.0.cxx)
+    }
+}
diff --git a/src/cxx.cc b/src/cxx.cc
index c0ef738..5dca531 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -22,6 +22,13 @@
   return s.length();
 }
 
+void cxxbridge1$cxx_string$clear(std::string &s) noexcept { s.clear(); }
+
+void cxxbridge1$cxx_string$reserve_total(std::string &s,
+                                         size_t new_cap) noexcept {
+  s.reserve(new_cap);
+}
+
 void cxxbridge1$cxx_string$push(std::string &s, const std::uint8_t *ptr,
                                 std::size_t len) noexcept {
   s.append(reinterpret_cast<const char *>(ptr), len);
@@ -31,12 +38,18 @@
 void cxxbridge1$string$new(rust::String *self) noexcept;
 void cxxbridge1$string$clone(rust::String *self,
                              const rust::String &other) noexcept;
-bool cxxbridge1$string$from(rust::String *self, const char *ptr,
-                            std::size_t len) noexcept;
+bool cxxbridge1$string$from_utf8(rust::String *self, const char *ptr,
+                                 std::size_t len) noexcept;
+bool cxxbridge1$string$from_utf16(rust::String *self, const char16_t *ptr,
+                                  std::size_t len) noexcept;
 void cxxbridge1$string$drop(rust::String *self) noexcept;
 const char *cxxbridge1$string$ptr(const rust::String *self) noexcept;
 std::size_t cxxbridge1$string$len(const rust::String *self) noexcept;
-void cxxbridge1$string$reserve_total(rust::String *self, size_t cap) noexcept;
+std::size_t cxxbridge1$string$capacity(const rust::String *self) noexcept;
+void cxxbridge1$string$reserve_additional(rust::String *self,
+                                          size_t additional) noexcept;
+void cxxbridge1$string$reserve_total(rust::String *self,
+                                     size_t new_cap) noexcept;
 
 // rust::Str
 void cxxbridge1$str$new(rust::Str *self) noexcept;
@@ -81,11 +94,17 @@
 String::~String() noexcept { cxxbridge1$string$drop(this); }
 
 static void initString(String *self, const char *s, std::size_t len) {
-  if (!cxxbridge1$string$from(self, s, len)) {
+  if (!cxxbridge1$string$from_utf8(self, s, len)) {
     panic<std::invalid_argument>("data for rust::String is not utf-8");
   }
 }
 
+static void initString(String *self, const char16_t *s, std::size_t len) {
+  if (!cxxbridge1$string$from_utf16(self, s, len)) {
+    panic<std::invalid_argument>("data for rust::String is not utf-16");
+  }
+}
+
 String::String(const std::string &s) { initString(this, s.data(), s.length()); }
 
 String::String(const char *s) {
@@ -100,6 +119,19 @@
              len);
 }
 
+String::String(const char16_t *s) {
+  assert(s != nullptr);
+  initString(this, s, std::char_traits<char16_t>::length(s));
+}
+
+String::String(const char16_t *s, std::size_t len) {
+  assert(s != nullptr || len == 0);
+  initString(this,
+             s == nullptr && len == 0 ? reinterpret_cast<const char16_t *>(2)
+                                      : s,
+             len);
+}
+
 String &String::operator=(const String &other) &noexcept {
   if (this != &other) {
     cxxbridge1$string$drop(this);
@@ -131,14 +163,24 @@
   return cxxbridge1$string$len(this);
 }
 
+bool String::empty() const noexcept { return this->size() == 0; }
+
 const char *String::c_str() noexcept {
   auto len = this->length();
-  cxxbridge1$string$reserve_total(this, len + 1);
+  cxxbridge1$string$reserve_additional(this, 1);
   auto ptr = this->data();
   const_cast<char *>(ptr)[len] = '\0';
   return ptr;
 }
 
+std::size_t String::capacity() const noexcept {
+  return cxxbridge1$string$capacity(this);
+}
+
+void String::reserve(std::size_t new_cap) noexcept {
+  cxxbridge1$string$reserve_total(this, new_cap);
+}
+
 String::iterator String::begin() noexcept {
   return const_cast<char *>(this->data());
 }
@@ -228,6 +270,8 @@
 
 std::size_t Str::length() const noexcept { return this->size(); }
 
+bool Str::empty() const noexcept { return this->size() == 0; }
+
 Str::const_iterator Str::begin() const noexcept { return this->cbegin(); }
 
 Str::const_iterator Str::end() const noexcept { return this->cend(); }
@@ -427,6 +471,13 @@
 } // namespace cxxbridge1
 } // namespace rust
 
+namespace {
+template <typename T>
+void destroy(T *ptr) {
+  ptr->~T();
+}
+} // namespace
+
 extern "C" {
 void cxxbridge1$unique_ptr$std$string$null(
     std::unique_ptr<std::string> *ptr) noexcept {
@@ -491,6 +542,18 @@
     ptr->~unique_ptr();                                                        \
   }
 
+#define STD_VECTOR_TRIVIAL_OPS(RUST_TYPE, CXX_TYPE)                            \
+  void cxxbridge1$std$vector$##RUST_TYPE##$push_back(                          \
+      std::vector<CXX_TYPE> *v, CXX_TYPE *value) noexcept {                    \
+    v->push_back(std::move(*value));                                           \
+    destroy(value);                                                            \
+  }                                                                            \
+  void cxxbridge1$std$vector$##RUST_TYPE##$pop_back(std::vector<CXX_TYPE> *v,  \
+                                                    CXX_TYPE *out) noexcept {  \
+    new (out) CXX_TYPE(std::move(v->back()));                                  \
+    v->pop_back();                                                             \
+  }
+
 #define RUST_VEC_EXTERNS(RUST_TYPE, CXX_TYPE)                                  \
   void cxxbridge1$rust_vec$##RUST_TYPE##$new(                                  \
       rust::Vec<CXX_TYPE> *ptr) noexcept;                                      \
@@ -503,7 +566,7 @@
   const CXX_TYPE *cxxbridge1$rust_vec$##RUST_TYPE##$data(                      \
       const rust::Vec<CXX_TYPE> *ptr) noexcept;                                \
   void cxxbridge1$rust_vec$##RUST_TYPE##$reserve_total(                        \
-      rust::Vec<CXX_TYPE> *ptr, std::size_t cap) noexcept;                     \
+      rust::Vec<CXX_TYPE> *ptr, std::size_t new_cap) noexcept;                 \
   void cxxbridge1$rust_vec$##RUST_TYPE##$set_len(rust::Vec<CXX_TYPE> *ptr,     \
                                                  std::size_t len) noexcept;
 
@@ -529,8 +592,8 @@
     return cxxbridge1$rust_vec$##RUST_TYPE##$data(this);                       \
   }                                                                            \
   template <>                                                                  \
-  void Vec<CXX_TYPE>::reserve_total(std::size_t cap) noexcept {                \
-    cxxbridge1$rust_vec$##RUST_TYPE##$reserve_total(this, cap);                \
+  void Vec<CXX_TYPE>::reserve_total(std::size_t new_cap) noexcept {            \
+    cxxbridge1$rust_vec$##RUST_TYPE##$reserve_total(this, new_cap);            \
   }                                                                            \
   template <>                                                                  \
   void Vec<CXX_TYPE>::set_len(std::size_t len) noexcept {                      \
@@ -603,10 +666,13 @@
   MACRO(f32, float)                                                            \
   MACRO(f64, double)
 
-#define FOR_EACH_STD_VECTOR(MACRO)                                             \
+#define FOR_EACH_TRIVIAL_STD_VECTOR(MACRO)                                     \
   FOR_EACH_NUMERIC(MACRO)                                                      \
   MACRO(usize, std::size_t)                                                    \
-  MACRO(isize, rust::isize)                                                    \
+  MACRO(isize, rust::isize)
+
+#define FOR_EACH_STD_VECTOR(MACRO)                                             \
+  FOR_EACH_TRIVIAL_STD_VECTOR(MACRO)                                           \
   MACRO(string, std::string)
 
 #define FOR_EACH_RUST_VEC(MACRO)                                               \
@@ -627,6 +693,7 @@
 
 extern "C" {
 FOR_EACH_STD_VECTOR(STD_VECTOR_OPS)
+FOR_EACH_TRIVIAL_STD_VECTOR(STD_VECTOR_TRIVIAL_OPS)
 FOR_EACH_RUST_VEC(RUST_VEC_EXTERNS)
 FOR_EACH_SHARED_PTR(SHARED_PTR_OPS)
 } // extern "C"
diff --git a/src/cxx_string.rs b/src/cxx_string.rs
index dce7053..626c2c8 100644
--- a/src/cxx_string.rs
+++ b/src/cxx_string.rs
@@ -19,6 +19,10 @@
     fn string_data(this: &CxxString) -> *const u8;
     #[link_name = "cxxbridge1$cxx_string$length"]
     fn string_length(this: &CxxString) -> usize;
+    #[link_name = "cxxbridge1$cxx_string$clear"]
+    fn string_clear(this: Pin<&mut CxxString>);
+    #[link_name = "cxxbridge1$cxx_string$reserve_total"]
+    fn string_reserve_total(this: Pin<&mut CxxString>, new_cap: usize);
     #[link_name = "cxxbridge1$cxx_string$push"]
     fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize);
 }
@@ -144,6 +148,49 @@
         String::from_utf8_lossy(self.as_bytes())
     }
 
+    /// Removes all characters from the string.
+    ///
+    /// Matches the behavior of C++ [std::string::clear][clear].
+    ///
+    /// Note: **unlike** the guarantee of Rust's `std::string::String::clear`,
+    /// the C++ standard does not require that capacity is unchanged by this
+    /// operation. In practice existing implementations do not change the
+    /// capacity but all pointers, references, and iterators into the string
+    /// contents are nevertheless invalidated.
+    ///
+    /// [clear]: https://en.cppreference.com/w/cpp/string/basic_string/clear
+    pub fn clear(self: Pin<&mut Self>) {
+        unsafe { string_clear(self) }
+    }
+
+    /// Ensures that this string's capacity is at least `additional` bytes
+    /// larger than its length.
+    ///
+    /// The capacity may be increased by more than `additional` bytes if it
+    /// chooses, to amortize the cost of frequent reallocations.
+    ///
+    /// **The meaning of the argument is not the same as
+    /// [std::string::reserve][reserve] in C++.** The C++ standard library and
+    /// Rust standard library both have a `reserve` method on strings, but in
+    /// C++ code the argument always refers to total capacity, whereas in Rust
+    /// code it always refers to additional capacity. This API on `CxxString`
+    /// follows the Rust convention, the same way that for the length accessor
+    /// we use the Rust conventional `len()` naming and not C++ `size()` or
+    /// `length()`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity overflows usize.
+    ///
+    /// [reserve]: https://en.cppreference.com/w/cpp/string/basic_string/reserve
+    pub fn reserve(self: Pin<&mut Self>, additional: usize) {
+        let new_cap = self
+            .len()
+            .checked_add(additional)
+            .expect("CxxString capacity overflow");
+        unsafe { string_reserve_total(self, new_cap) }
+    }
+
     /// Appends a given string slice onto the end of this C++ string.
     pub fn push_str(self: Pin<&mut Self>, s: &str) {
         self.push_bytes(s.as_bytes());
@@ -213,6 +260,7 @@
     space: MaybeUninit<[usize; 8]>,
 }
 
+#[allow(missing_docs)]
 impl StackString {
     pub fn new() -> Self {
         StackString {
@@ -222,9 +270,11 @@
 
     pub unsafe fn init(&mut self, value: impl AsRef<[u8]>) -> Pin<&mut CxxString> {
         let value = value.as_ref();
-        let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
-        string_init(this, value.as_ptr(), value.len());
-        Pin::new_unchecked(&mut *this.as_mut_ptr())
+        unsafe {
+            let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
+            string_init(this, value.as_ptr(), value.len());
+            Pin::new_unchecked(&mut *this.as_mut_ptr())
+        }
     }
 }
 
diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs
index 1643341..d1fa23a 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -8,9 +8,8 @@
 use core::fmt::{self, Debug};
 use core::iter::FusedIterator;
 use core::marker::{PhantomData, PhantomPinned};
-use core::mem;
+use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::pin::Pin;
-use core::ptr;
 use core::slice;
 
 /// Binding to C++ `std::vector<T, std::allocator<T>>`.
@@ -23,7 +22,13 @@
 /// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
 #[repr(C, packed)]
 pub struct CxxVector<T> {
-    _private: [T; 0],
+    // A thing, because repr(C) structs are not allowed to consist exclusively
+    // of PhantomData fields.
+    _void: [c_void; 0],
+    // The conceptual vector elements to ensure that autotraits are propagated
+    // correctly, e.g. CxxVector is UnwindSafe iff T is.
+    _elements: PhantomData<[T]>,
+    // Prevent unpin operation from Pin<&mut CxxVector<T>> to &mut CxxVector<T>.
     _pinned: PhantomData<PhantomPinned>,
 }
 
@@ -81,8 +86,10 @@
     /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
     pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
         let this = self as *const CxxVector<T> as *mut CxxVector<T>;
-        let ptr = T::__get_unchecked(this, pos) as *const T;
-        &*ptr
+        unsafe {
+            let ptr = T::__get_unchecked(this, pos) as *const T;
+            &*ptr
+        }
     }
 
     /// Returns a pinned mutable reference to an element without doing bounds
@@ -97,8 +104,10 @@
     ///
     /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
     pub unsafe fn index_unchecked_mut(self: Pin<&mut Self>, pos: usize) -> Pin<&mut T> {
-        let ptr = T::__get_unchecked(self.get_unchecked_mut(), pos);
-        Pin::new_unchecked(&mut *ptr)
+        unsafe {
+            let ptr = T::__get_unchecked(self.get_unchecked_mut(), pos);
+            Pin::new_unchecked(&mut *ptr)
+        }
     }
 
     /// Returns a slice to the underlying contiguous array of elements.
@@ -146,6 +155,39 @@
     pub fn iter_mut(self: Pin<&mut Self>) -> IterMut<T> {
         IterMut { v: self, index: 0 }
     }
+
+    /// Appends an element to the back of the vector.
+    ///
+    /// Matches the behavior of C++ [std::vector\<T\>::push_back][push_back].
+    ///
+    /// [push_back]: https://en.cppreference.com/w/cpp/container/vector/push_back
+    pub fn push(self: Pin<&mut Self>, value: T)
+    where
+        T: ExternType<Kind = Trivial>,
+    {
+        let mut value = ManuallyDrop::new(value);
+        unsafe {
+            // C++ calls move constructor followed by destructor on `value`.
+            T::__push_back(self, &mut value);
+        }
+    }
+
+    /// Removes the last element from a vector and returns it, or `None` if the
+    /// vector is empty.
+    pub fn pop(self: Pin<&mut Self>) -> Option<T>
+    where
+        T: ExternType<Kind = Trivial>,
+    {
+        if self.is_empty() {
+            None
+        } else {
+            let mut value = MaybeUninit::uninit();
+            Some(unsafe {
+                T::__pop_back(self, &mut value);
+                value.assume_init()
+            })
+        }
+    }
 }
 
 /// Iterator over elements of a `CxxVector` by shared reference.
@@ -296,19 +338,62 @@
     #[doc(hidden)]
     unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
     #[doc(hidden)]
-    fn __unique_ptr_null() -> *mut c_void;
+    unsafe fn __push_back(v: Pin<&mut CxxVector<Self>>, value: &mut ManuallyDrop<Self>) {
+        // Opaque C type vector elements do not get this method because they can
+        // never exist by value on the Rust side of the bridge.
+        let _ = v;
+        let _ = value;
+        unreachable!()
+    }
     #[doc(hidden)]
-    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
+    unsafe fn __pop_back(v: Pin<&mut CxxVector<Self>>, out: &mut MaybeUninit<Self>) {
+        // Opaque C type vector elements do not get this method because they can
+        // never exist by value on the Rust side of the bridge.
+        let _ = v;
+        let _ = out;
+        unreachable!()
+    }
     #[doc(hidden)]
-    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
+    fn __unique_ptr_null() -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
-    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
+    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
-    unsafe fn __unique_ptr_drop(repr: *mut c_void);
+    unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self>;
+    #[doc(hidden)]
+    unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self>;
+    #[doc(hidden)]
+    unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>);
+}
+
+macro_rules! vector_element_by_value_methods {
+    (opaque, $segment:expr, $ty:ty) => {};
+    (trivial, $segment:expr, $ty:ty) => {
+        #[doc(hidden)]
+        unsafe fn __push_back(v: Pin<&mut CxxVector<$ty>>, value: &mut ManuallyDrop<$ty>) {
+            extern "C" {
+                attr! {
+                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$push_back")]
+                    fn __push_back(_: Pin<&mut CxxVector<$ty>>, _: &mut ManuallyDrop<$ty>);
+                }
+            }
+            unsafe { __push_back(v, value) }
+        }
+        #[doc(hidden)]
+        unsafe fn __pop_back(v: Pin<&mut CxxVector<$ty>>, out: &mut MaybeUninit<$ty>) {
+            extern "C" {
+                attr! {
+                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$pop_back")]
+                    fn __pop_back(_: Pin<&mut CxxVector<$ty>>, _: &mut MaybeUninit<$ty>);
+                }
+            }
+            unsafe { __pop_back(v, out) }
+        }
+    };
 }
 
 macro_rules! impl_vector_element {
-    ($segment:expr, $name:expr, $ty:ty) => {
+    ($kind:ident, $segment:expr, $name:expr, $ty:ty) => {
+        const_assert_eq!(0, mem::size_of::<CxxVector<$ty>>());
         const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());
 
         unsafe impl VectorElement for $ty {
@@ -334,61 +419,62 @@
                         fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
                     }
                 }
-                __get_unchecked(v, pos)
+                unsafe { __get_unchecked(v, pos) }
             }
+            vector_element_by_value_methods!($kind, $segment, $ty);
             #[doc(hidden)]
-            fn __unique_ptr_null() -> *mut c_void {
+            fn __unique_ptr_null() -> MaybeUninit<*mut c_void> {
                 extern "C" {
                     attr! {
                         #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
-                        fn __unique_ptr_null(this: *mut *mut c_void);
+                        fn __unique_ptr_null(this: *mut MaybeUninit<*mut c_void>);
                     }
                 }
-                let mut repr = ptr::null_mut::<c_void>();
+                let mut repr = MaybeUninit::uninit();
                 unsafe { __unique_ptr_null(&mut repr) }
                 repr
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
+            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void> {
                 extern "C" {
                     attr! {
                         #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
-                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
+                        fn __unique_ptr_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxVector<$ty>);
                     }
                 }
-                let mut repr = ptr::null_mut::<c_void>();
-                __unique_ptr_raw(&mut repr, raw);
+                let mut repr = MaybeUninit::uninit();
+                unsafe { __unique_ptr_raw(&mut repr, raw) }
                 repr
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
+            unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self> {
                 extern "C" {
                     attr! {
                         #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
-                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
+                        fn __unique_ptr_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxVector<$ty>;
                     }
                 }
-                __unique_ptr_get(&repr)
+                unsafe { __unique_ptr_get(&repr) }
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
+            unsafe fn __unique_ptr_release(mut repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self> {
                 extern "C" {
                     attr! {
                         #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
-                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
+                        fn __unique_ptr_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxVector<$ty>;
                     }
                 }
-                __unique_ptr_release(&mut repr)
+                unsafe { __unique_ptr_release(&mut repr) }
             }
             #[doc(hidden)]
-            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
+            unsafe fn __unique_ptr_drop(mut repr: MaybeUninit<*mut c_void>) {
                 extern "C" {
                     attr! {
                         #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
-                        fn __unique_ptr_drop(this: *mut *mut c_void);
+                        fn __unique_ptr_drop(this: *mut MaybeUninit<*mut c_void>);
                     }
                 }
-                __unique_ptr_drop(&mut repr);
+                unsafe { __unique_ptr_drop(&mut repr) }
             }
         }
     };
@@ -396,7 +482,7 @@
 
 macro_rules! impl_vector_element_for_primitive {
     ($ty:ident) => {
-        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
+        impl_vector_element!(trivial, stringify!($ty), stringify!($ty), $ty);
     };
 }
 
@@ -413,4 +499,4 @@
 impl_vector_element_for_primitive!(f32);
 impl_vector_element_for_primitive!(f64);
 
-impl_vector_element!("string", "CxxString", CxxString);
+impl_vector_element!(opaque, "string", "CxxString", CxxString);
diff --git a/src/exception.rs b/src/exception.rs
index f61e8fa..2ae470e 100644
--- a/src/exception.rs
+++ b/src/exception.rs
@@ -1,5 +1,5 @@
 use alloc::boxed::Box;
-use core::fmt::{self, Debug, Display};
+use core::fmt::{self, Display};
 
 /// Exception thrown from an `extern "C++"` function.
 #[derive(Debug)]
@@ -16,6 +16,7 @@
 impl std::error::Error for Exception {}
 
 impl Exception {
+    #[allow(missing_docs)]
     pub fn what(&self) -> &str {
         &self.what
     }
diff --git a/src/extern_type.rs b/src/extern_type.rs
index 35057ac..8c9c286 100644
--- a/src/extern_type.rs
+++ b/src/extern_type.rs
@@ -167,6 +167,7 @@
     /// indirection.
     pub enum Trivial {}
 
+    #[allow(missing_docs)]
     pub trait Kind: private::Sealed {}
     impl Kind for Opaque {}
     impl Kind for Trivial {}
diff --git a/src/function.rs b/src/function.rs
index 1166b3d..f0a2010 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -1,5 +1,9 @@
+#![allow(missing_docs)]
+
+use core::ffi::c_void;
+
 #[repr(C)]
 pub struct FatFunction {
-    pub trampoline: *const (),
-    pub ptr: *const (),
+    pub trampoline: *const c_void,
+    pub ptr: *const c_void,
 }
diff --git a/src/lib.rs b/src/lib.rs
index 19a708c..9880e71 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -364,8 +364,10 @@
 //! </table>
 
 #![no_std]
-#![doc(html_root_url = "https://docs.rs/cxx/1.0.42")]
-#![deny(improper_ctypes)]
+#![doc(html_root_url = "https://docs.rs/cxx/1.0.54")]
+#![deny(improper_ctypes, improper_ctypes_definitions, missing_docs)]
+#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))]
+#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
 #![allow(non_camel_case_types)]
 #![allow(
     clippy::cognitive_complexity,
@@ -486,3 +488,6 @@
     a b c d e f g h i j k l m n o p q r s t u v w x y z
     __ // underscore
 }
+
+#[repr(transparent)]
+struct void(core::ffi::c_void);
diff --git a/src/memory.rs b/src/memory.rs
index 441d3d8..fd8df12 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -4,5 +4,6 @@
 
 pub use crate::shared_ptr::SharedPtrTarget;
 pub use crate::unique_ptr::UniquePtrTarget;
+pub use crate::weak_ptr::WeakPtrTarget;
 #[doc(no_inline)]
 pub use cxx::{SharedPtr, UniquePtr};
diff --git a/src/opaque.rs b/src/opaque.rs
index 3c8f536..e0f8ce2 100644
--- a/src/opaque.rs
+++ b/src/opaque.rs
@@ -1,3 +1,6 @@
+#![allow(missing_docs)]
+
+use crate::void;
 use core::marker::{PhantomData, PhantomPinned};
 use core::mem;
 
@@ -9,7 +12,7 @@
 // . !Unpin
 #[repr(C, packed)]
 pub struct Opaque {
-    _private: [*const u8; 0],
+    _private: [*const void; 0],
     _pinned: PhantomData<PhantomPinned>,
 }
 
diff --git a/src/result.rs b/src/result.rs
index f41639a..d7a31f0 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -1,3 +1,5 @@
+#![allow(missing_docs)]
+
 use crate::exception::Exception;
 use alloc::boxed::Box;
 use alloc::string::{String, ToString};
@@ -26,16 +28,16 @@
 {
     match result {
         Ok(ok) => {
-            ptr::write(ret, ok);
+            unsafe { ptr::write(ret, ok) }
             Result { ok: ptr::null() }
         }
-        Err(err) => to_c_error(err.to_string()),
+        Err(err) => unsafe { to_c_error(err.to_string()) },
     }
 }
 
 unsafe fn to_c_error(msg: String) -> Result {
     let mut msg = msg;
-    msg.as_mut_vec().push(b'\0');
+    unsafe { msg.as_mut_vec() }.push(b'\0');
     let ptr = msg.as_ptr();
     let len = msg.len();
 
@@ -44,22 +46,24 @@
         fn error(ptr: *const u8, len: usize) -> NonNull<u8>;
     }
 
-    let copy = error(ptr, len);
+    let copy = unsafe { error(ptr, len) };
     let err = PtrLen { ptr: copy, len };
     Result { err }
 }
 
 impl Result {
     pub unsafe fn exception(self) -> StdResult<(), Exception> {
-        if self.ok.is_null() {
-            Ok(())
-        } else {
-            let err = self.err;
-            let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
-            let s = str::from_utf8_unchecked_mut(slice);
-            Err(Exception {
-                what: Box::from_raw(s),
-            })
+        unsafe {
+            if self.ok.is_null() {
+                Ok(())
+            } else {
+                let err = self.err;
+                let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
+                let s = str::from_utf8_unchecked_mut(slice);
+                Err(Exception {
+                    what: Box::from_raw(s),
+                })
+            }
         }
     }
 }
diff --git a/src/rust_slice.rs b/src/rust_slice.rs
index b4b5f2c..0696311 100644
--- a/src/rust_slice.rs
+++ b/src/rust_slice.rs
@@ -1,41 +1,66 @@
-use core::mem;
+#![allow(missing_docs)]
+
+use core::mem::{self, MaybeUninit};
 use core::ptr::{self, NonNull};
 use core::slice;
 
+// ABI compatible with C++ rust::Slice<T> (not necessarily &[T]).
 #[repr(C)]
 pub struct RustSlice {
-    pub(crate) repr: NonNull<[()]>,
+    repr: [MaybeUninit<usize>; mem::size_of::<NonNull<[()]>>() / mem::size_of::<usize>()],
 }
 
 impl RustSlice {
     pub fn from_ref<T>(slice: &[T]) -> Self {
-        let ptr = ptr::slice_from_raw_parts::<()>(slice.as_ptr().cast(), slice.len());
-        RustSlice {
-            repr: unsafe { NonNull::new_unchecked(ptr as *mut _) },
-        }
+        let ptr = NonNull::from(slice).cast::<T>();
+        let len = slice.len();
+        Self::from_raw_parts(ptr, len)
     }
 
     pub fn from_mut<T>(slice: &mut [T]) -> Self {
-        let ptr = ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len());
-        RustSlice {
-            repr: unsafe { NonNull::new_unchecked(ptr) },
-        }
+        let ptr = NonNull::from(&mut *slice).cast::<T>();
+        let len = slice.len();
+        Self::from_raw_parts(ptr, len)
     }
 
     pub unsafe fn as_slice<'a, T>(self) -> &'a [T] {
-        let ptr = self.repr.as_ptr();
-        let len = self.repr.as_ref().len();
-        slice::from_raw_parts(ptr.cast(), len)
+        let ptr = self.as_non_null_ptr().as_ptr();
+        let len = self.len();
+        unsafe { slice::from_raw_parts(ptr, len) }
     }
 
     pub unsafe fn as_mut_slice<'a, T>(self) -> &'a mut [T] {
-        let ptr = self.repr.as_ptr();
-        let len = self.repr.as_ref().len();
-        slice::from_raw_parts_mut(ptr.cast(), len)
+        let ptr = self.as_non_null_ptr().as_ptr();
+        let len = self.len();
+        unsafe { slice::from_raw_parts_mut(ptr, len) }
+    }
+
+    pub(crate) fn from_raw_parts<T>(ptr: NonNull<T>, len: usize) -> Self {
+        // TODO: use NonNull::from_raw_parts(ptr.cast(), len) when stable.
+        // https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.from_raw_parts
+        // https://github.com/rust-lang/rust/issues/81513
+        let ptr = ptr::slice_from_raw_parts_mut(ptr.as_ptr().cast(), len);
+        unsafe { mem::transmute::<NonNull<[()]>, RustSlice>(NonNull::new_unchecked(ptr)) }
+    }
+
+    pub(crate) fn as_non_null_ptr<T>(&self) -> NonNull<T> {
+        let rust_slice = RustSlice { repr: self.repr };
+        let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
+        repr.cast()
+    }
+
+    pub(crate) fn len(&self) -> usize {
+        let rust_slice = RustSlice { repr: self.repr };
+        let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
+        // TODO: use repr.len() when stable.
+        // https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.len
+        // https://github.com/rust-lang/rust/issues/71146
+        unsafe { repr.as_ref() }.len()
     }
 }
 
+const_assert_eq!(mem::size_of::<NonNull<[()]>>(), mem::size_of::<RustSlice>());
 const_assert_eq!(
-    mem::size_of::<Option<RustSlice>>(),
-    mem::size_of::<RustSlice>(),
+    mem::align_of::<NonNull<[()]>>(),
+    mem::align_of::<RustSlice>(),
 );
diff --git a/src/rust_str.rs b/src/rust_str.rs
index 9bc2614..b1b46e3 100644
--- a/src/rust_str.rs
+++ b/src/rust_str.rs
@@ -1,21 +1,28 @@
-use core::mem;
+#![allow(missing_docs)]
+
+use core::mem::{self, MaybeUninit};
 use core::ptr::NonNull;
 use core::str;
 
+// ABI compatible with C++ rust::Str (not necessarily &str).
 #[repr(C)]
 pub struct RustStr {
-    repr: NonNull<str>,
+    repr: [MaybeUninit<usize>; mem::size_of::<NonNull<str>>() / mem::size_of::<usize>()],
 }
 
 impl RustStr {
     pub fn from(repr: &str) -> Self {
         let repr = NonNull::from(repr);
-        RustStr { repr }
+        unsafe { mem::transmute::<NonNull<str>, RustStr>(repr) }
     }
 
     pub unsafe fn as_str<'a>(self) -> &'a str {
-        &*self.repr.as_ptr()
+        unsafe {
+            let repr = mem::transmute::<RustStr, NonNull<str>>(self);
+            &*repr.as_ptr()
+        }
     }
 }
 
-const_assert_eq!(mem::size_of::<Option<RustStr>>(), mem::size_of::<RustStr>());
+const_assert_eq!(mem::size_of::<NonNull<str>>(), mem::size_of::<RustStr>());
+const_assert_eq!(mem::align_of::<NonNull<str>>(), mem::align_of::<RustStr>());
diff --git a/src/rust_string.rs b/src/rust_string.rs
index a5fa3f4..051e35c 100644
--- a/src/rust_string.rs
+++ b/src/rust_string.rs
@@ -1,14 +1,18 @@
-use alloc::string::String;
-use core::mem;
+#![allow(missing_docs)]
 
+use alloc::string::String;
+use core::mem::{self, MaybeUninit};
+use core::ptr;
+
+// ABI compatible with C++ rust::String (not necessarily alloc::string::String).
 #[repr(C)]
 pub struct RustString {
-    repr: String,
+    repr: [MaybeUninit<usize>; mem::size_of::<String>() / mem::size_of::<usize>()],
 }
 
 impl RustString {
     pub fn from(s: String) -> Self {
-        RustString { repr: s }
+        unsafe { mem::transmute::<String, RustString>(s) }
     }
 
     pub fn from_ref(s: &String) -> &Self {
@@ -20,17 +24,24 @@
     }
 
     pub fn into_string(self) -> String {
-        self.repr
+        unsafe { mem::transmute::<RustString, String>(self) }
     }
 
     pub fn as_string(&self) -> &String {
-        &self.repr
+        unsafe { &*(self as *const RustString as *const String) }
     }
 
     pub fn as_mut_string(&mut self) -> &mut String {
-        &mut self.repr
+        unsafe { &mut *(self as *mut RustString as *mut String) }
     }
 }
 
-const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<String>());
-const_assert_eq!(mem::align_of::<usize>(), mem::align_of::<String>());
+impl Drop for RustString {
+    fn drop(&mut self) {
+        unsafe { ptr::drop_in_place(self.as_mut_string()) }
+    }
+}
+
+const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<RustString>());
+const_assert_eq!(mem::size_of::<String>(), mem::size_of::<RustString>());
+const_assert_eq!(mem::align_of::<String>(), mem::align_of::<RustString>());
diff --git a/src/rust_type.rs b/src/rust_type.rs
index 7bcf440..eacb530 100644
--- a/src/rust_type.rs
+++ b/src/rust_type.rs
@@ -1,3 +1,5 @@
+#![allow(missing_docs)]
+
 pub unsafe trait RustType {}
 pub unsafe trait ImplBox {}
 pub unsafe trait ImplVec {}
diff --git a/src/rust_vec.rs b/src/rust_vec.rs
index 126fdbf..9f4484d 100644
--- a/src/rust_vec.rs
+++ b/src/rust_vec.rs
@@ -1,20 +1,27 @@
+#![allow(missing_docs)]
+
 use crate::rust_string::RustString;
 use alloc::string::String;
 use alloc::vec::Vec;
-use core::mem::ManuallyDrop;
+use core::ffi::c_void;
+use core::marker::PhantomData;
+use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::ptr;
 
+// ABI compatible with C++ rust::Vec<T> (not necessarily alloc::vec::Vec<T>).
 #[repr(C)]
 pub struct RustVec<T> {
-    pub(crate) repr: Vec<T>,
+    repr: [MaybeUninit<usize>; mem::size_of::<Vec<c_void>>() / mem::size_of::<usize>()],
+    marker: PhantomData<Vec<T>>,
 }
 
 impl<T> RustVec<T> {
     pub fn new() -> Self {
-        RustVec { repr: Vec::new() }
+        Self::from(Vec::new())
     }
 
     pub fn from(v: Vec<T>) -> Self {
-        RustVec { repr: v }
+        unsafe { mem::transmute::<Vec<T>, RustVec<T>>(v) }
     }
 
     pub fn from_ref(v: &Vec<T>) -> &Self {
@@ -26,38 +33,39 @@
     }
 
     pub fn into_vec(self) -> Vec<T> {
-        self.repr
+        unsafe { mem::transmute::<RustVec<T>, Vec<T>>(self) }
     }
 
     pub fn as_vec(&self) -> &Vec<T> {
-        &self.repr
+        unsafe { &*(self as *const RustVec<T> as *const Vec<T>) }
     }
 
     pub fn as_mut_vec(&mut self) -> &mut Vec<T> {
-        &mut self.repr
+        unsafe { &mut *(self as *mut RustVec<T> as *mut Vec<T>) }
     }
 
     pub fn len(&self) -> usize {
-        self.repr.len()
+        self.as_vec().len()
     }
 
     pub fn capacity(&self) -> usize {
-        self.repr.capacity()
+        self.as_vec().capacity()
     }
 
     pub fn as_ptr(&self) -> *const T {
-        self.repr.as_ptr()
+        self.as_vec().as_ptr()
     }
 
-    pub fn reserve_total(&mut self, cap: usize) {
-        let len = self.repr.len();
-        if cap > len {
-            self.repr.reserve(cap - len);
+    pub fn reserve_total(&mut self, new_cap: usize) {
+        let vec = self.as_mut_vec();
+        if new_cap > vec.capacity() {
+            let additional = new_cap - vec.len();
+            vec.reserve(additional);
         }
     }
 
     pub unsafe fn set_len(&mut self, len: usize) {
-        self.repr.set_len(len);
+        unsafe { self.as_mut_vec().set_len(len) }
     }
 }
 
@@ -79,7 +87,7 @@
     }
 
     pub fn into_vec_string(self) -> Vec<String> {
-        let mut v = ManuallyDrop::new(self.repr);
+        let mut v = ManuallyDrop::new(self.into_vec());
         let ptr = v.as_mut_ptr().cast::<String>();
         let len = v.len();
         let cap = v.capacity();
@@ -87,10 +95,16 @@
     }
 
     pub fn as_vec_string(&self) -> &Vec<String> {
-        unsafe { &*(&self.repr as *const Vec<RustString> as *const Vec<String>) }
+        unsafe { &*(self as *const RustVec<RustString> as *const Vec<String>) }
     }
 
     pub fn as_mut_vec_string(&mut self) -> &mut Vec<String> {
-        unsafe { &mut *(&mut self.repr as *mut Vec<RustString> as *mut Vec<String>) }
+        unsafe { &mut *(self as *mut RustVec<RustString> as *mut Vec<String>) }
+    }
+}
+
+impl<T> Drop for RustVec<T> {
+    fn drop(&mut self) {
+        unsafe { ptr::drop_in_place(self.as_mut_vec()) }
     }
 }
diff --git a/src/shared_ptr.rs b/src/shared_ptr.rs
index 66b988b..317773d 100644
--- a/src/shared_ptr.rs
+++ b/src/shared_ptr.rs
@@ -15,7 +15,7 @@
 where
     T: SharedPtrTarget,
 {
-    repr: [*mut c_void; 2],
+    repr: [MaybeUninit<*mut c_void>; 2],
     ty: PhantomData<T>,
 }
 
@@ -216,7 +216,7 @@
                         fn __null(new: *mut c_void);
                     }
                 }
-                __null(new);
+                unsafe { __null(new) }
             }
             #[doc(hidden)]
             unsafe fn __new(value: Self, new: *mut c_void) {
@@ -226,7 +226,7 @@
                         fn __uninit(new: *mut c_void) -> *mut c_void;
                     }
                 }
-                __uninit(new).cast::<$ty>().write(value);
+                unsafe { __uninit(new).cast::<$ty>().write(value) }
             }
             #[doc(hidden)]
             unsafe fn __clone(this: *const c_void, new: *mut c_void) {
@@ -236,7 +236,7 @@
                         fn __clone(this: *const c_void, new: *mut c_void);
                     }
                 }
-                __clone(this, new);
+                unsafe { __clone(this, new) }
             }
             #[doc(hidden)]
             unsafe fn __get(this: *const c_void) -> *const Self {
@@ -246,7 +246,7 @@
                         fn __get(this: *const c_void) -> *const c_void;
                     }
                 }
-                __get(this).cast()
+                unsafe { __get(this) }.cast()
             }
             #[doc(hidden)]
             unsafe fn __drop(this: *mut c_void) {
@@ -256,7 +256,7 @@
                         fn __drop(this: *mut c_void);
                     }
                 }
-                __drop(this);
+                unsafe { __drop(this) }
             }
         }
     };
diff --git a/src/symbols/exception.rs b/src/symbols/exception.rs
index 0c1bb87..cf0701b 100644
--- a/src/symbols/exception.rs
+++ b/src/symbols/exception.rs
@@ -4,7 +4,7 @@
 
 #[export_name = "cxxbridge1$exception"]
 unsafe extern "C" fn exception(ptr: *const u8, len: usize) -> *const u8 {
-    let slice = slice::from_raw_parts(ptr, len);
+    let slice = unsafe { slice::from_raw_parts(ptr, len) };
     let boxed = String::from_utf8_lossy(slice).into_owned().into_boxed_str();
     Box::leak(boxed).as_ptr()
 }
diff --git a/src/symbols/rust_slice.rs b/src/symbols/rust_slice.rs
index 055b4de..df215ac 100644
--- a/src/symbols/rust_slice.rs
+++ b/src/symbols/rust_slice.rs
@@ -3,20 +3,18 @@
 use core::ptr::{self, NonNull};
 
 #[export_name = "cxxbridge1$slice$new"]
-unsafe extern "C" fn slice_new(this: &mut MaybeUninit<RustSlice>, ptr: *const (), len: usize) {
-    let ptr = ptr::slice_from_raw_parts(ptr, len);
-    let rust_slice = RustSlice {
-        repr: NonNull::new_unchecked(ptr as *mut _),
-    };
-    ptr::write(this.as_mut_ptr(), rust_slice);
+unsafe extern "C" fn slice_new(this: &mut MaybeUninit<RustSlice>, ptr: NonNull<()>, len: usize) {
+    let this = this.as_mut_ptr();
+    let rust_slice = RustSlice::from_raw_parts(ptr, len);
+    unsafe { ptr::write(this, rust_slice) }
 }
 
 #[export_name = "cxxbridge1$slice$ptr"]
-unsafe extern "C" fn slice_ptr(this: &RustSlice) -> *const () {
-    this.repr.as_ptr().cast()
+unsafe extern "C" fn slice_ptr(this: &RustSlice) -> NonNull<()> {
+    this.as_non_null_ptr()
 }
 
 #[export_name = "cxxbridge1$slice$len"]
 unsafe extern "C" fn slice_len(this: &RustSlice) -> usize {
-    this.repr.as_ref().len()
+    this.len()
 }
diff --git a/src/symbols/rust_str.rs b/src/symbols/rust_str.rs
index a9e84ef..3d5ec34 100644
--- a/src/symbols/rust_str.rs
+++ b/src/symbols/rust_str.rs
@@ -6,20 +6,24 @@
 
 #[export_name = "cxxbridge1$str$new"]
 unsafe extern "C" fn str_new(this: &mut MaybeUninit<&str>) {
-    ptr::write(this.as_mut_ptr(), "");
+    let this = this.as_mut_ptr();
+    unsafe { ptr::write(this, "") }
 }
 
 #[export_name = "cxxbridge1$str$ref"]
 unsafe extern "C" fn str_ref<'a>(this: &mut MaybeUninit<&'a str>, string: &'a String) {
-    ptr::write(this.as_mut_ptr(), string.as_str());
+    let this = this.as_mut_ptr();
+    let s = string.as_str();
+    unsafe { ptr::write(this, s) }
 }
 
 #[export_name = "cxxbridge1$str$from"]
 unsafe extern "C" fn str_from(this: &mut MaybeUninit<&str>, ptr: *const u8, len: usize) -> bool {
-    let slice = slice::from_raw_parts(ptr, len);
+    let slice = unsafe { slice::from_raw_parts(ptr, len) };
     match str::from_utf8(slice) {
         Ok(s) => {
-            ptr::write(this.as_mut_ptr(), s);
+            let this = this.as_mut_ptr();
+            unsafe { ptr::write(this, s) }
             true
         }
         Err(_) => false,
diff --git a/src/symbols/rust_string.rs b/src/symbols/rust_string.rs
index 91fd78a..49d4069 100644
--- a/src/symbols/rust_string.rs
+++ b/src/symbols/rust_string.rs
@@ -7,24 +7,47 @@
 
 #[export_name = "cxxbridge1$string$new"]
 unsafe extern "C" fn string_new(this: &mut MaybeUninit<String>) {
-    ptr::write(this.as_mut_ptr(), String::new());
+    let this = this.as_mut_ptr();
+    let new = String::new();
+    unsafe { ptr::write(this, new) }
 }
 
 #[export_name = "cxxbridge1$string$clone"]
 unsafe extern "C" fn string_clone(this: &mut MaybeUninit<String>, other: &String) {
-    ptr::write(this.as_mut_ptr(), other.clone());
+    let this = this.as_mut_ptr();
+    let clone = other.clone();
+    unsafe { ptr::write(this, clone) }
 }
 
-#[export_name = "cxxbridge1$string$from"]
-unsafe extern "C" fn string_from(
+#[export_name = "cxxbridge1$string$from_utf8"]
+unsafe extern "C" fn string_from_utf8(
     this: &mut MaybeUninit<String>,
     ptr: *const u8,
     len: usize,
 ) -> bool {
-    let slice = slice::from_raw_parts(ptr, len);
+    let slice = unsafe { slice::from_raw_parts(ptr, len) };
     match str::from_utf8(slice) {
         Ok(s) => {
-            ptr::write(this.as_mut_ptr(), s.to_owned());
+            let this = this.as_mut_ptr();
+            let owned = s.to_owned();
+            unsafe { ptr::write(this, owned) }
+            true
+        }
+        Err(_) => false,
+    }
+}
+
+#[export_name = "cxxbridge1$string$from_utf16"]
+unsafe extern "C" fn string_from_utf16(
+    this: &mut MaybeUninit<String>,
+    ptr: *const u16,
+    len: usize,
+) -> bool {
+    let slice = unsafe { slice::from_raw_parts(ptr, len) };
+    match String::from_utf16(slice) {
+        Ok(s) => {
+            let this = this.as_mut_ptr();
+            unsafe { ptr::write(this, s) }
             true
         }
         Err(_) => false,
@@ -33,7 +56,7 @@
 
 #[export_name = "cxxbridge1$string$drop"]
 unsafe extern "C" fn string_drop(this: &mut ManuallyDrop<String>) {
-    ManuallyDrop::drop(this);
+    unsafe { ManuallyDrop::drop(this) }
 }
 
 #[export_name = "cxxbridge1$string$ptr"]
@@ -46,7 +69,20 @@
     this.len()
 }
 
+#[export_name = "cxxbridge1$string$capacity"]
+unsafe extern "C" fn string_capacity(this: &String) -> usize {
+    this.capacity()
+}
+
+#[export_name = "cxxbridge1$string$reserve_additional"]
+unsafe extern "C" fn string_reserve_additional(this: &mut String, additional: usize) {
+    this.reserve(additional);
+}
+
 #[export_name = "cxxbridge1$string$reserve_total"]
-unsafe extern "C" fn string_reserve_total(this: &mut String, cap: usize) {
-    this.reserve(cap);
+unsafe extern "C" fn string_reserve_total(this: &mut String, new_cap: usize) {
+    if new_cap > this.capacity() {
+        let additional = new_cap - this.len();
+        this.reserve(additional);
+    }
 }
diff --git a/src/symbols/rust_vec.rs b/src/symbols/rust_vec.rs
index a26a156..6f2dab9 100644
--- a/src/symbols/rust_vec.rs
+++ b/src/symbols/rust_vec.rs
@@ -7,50 +7,51 @@
 
 macro_rules! rust_vec_shims {
     ($segment:expr, $ty:ty) => {
-        const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<Vec<$ty>>());
-        const_assert_eq!(mem::align_of::<usize>(), mem::align_of::<Vec<$ty>>());
+        const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<RustVec<$ty>>());
+        const_assert_eq!(mem::size_of::<Vec<$ty>>(), mem::size_of::<RustVec<$ty>>());
+        const_assert_eq!(mem::align_of::<Vec<$ty>>(), mem::align_of::<RustVec<$ty>>());
 
         const _: () = {
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$new")]
                 unsafe extern "C" fn __new(this: *mut RustVec<$ty>) {
-                    ptr::write(this, RustVec { repr: Vec::new() });
+                    unsafe { ptr::write(this, RustVec::new()) }
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$drop")]
                 unsafe extern "C" fn __drop(this: *mut RustVec<$ty>) {
-                    ptr::drop_in_place(this);
+                    unsafe { ptr::drop_in_place(this) }
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$len")]
                 unsafe extern "C" fn __len(this: *const RustVec<$ty>) -> usize {
-                    (*this).repr.len()
+                    unsafe { &*this }.len()
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$capacity")]
                 unsafe extern "C" fn __capacity(this: *const RustVec<$ty>) -> usize {
-                    (*this).repr.capacity()
+                    unsafe { &*this }.capacity()
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$data")]
                 unsafe extern "C" fn __data(this: *const RustVec<$ty>) -> *const $ty {
-                    (*this).repr.as_ptr()
+                    unsafe { &*this }.as_ptr()
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$reserve_total")]
-                unsafe extern "C" fn __reserve_total(this: *mut RustVec<$ty>, cap: usize) {
-                    (*this).reserve_total(cap);
+                unsafe extern "C" fn __reserve_total(this: *mut RustVec<$ty>, new_cap: usize) {
+                    unsafe { &mut *this }.reserve_total(new_cap);
                 }
             }
             attr! {
                 #[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$set_len")]
                 unsafe extern "C" fn __set_len(this: *mut RustVec<$ty>, len: usize) {
-                    (*this).repr.set_len(len);
+                    unsafe { (*this).set_len(len) }
                 }
             }
         };
diff --git a/src/unique_ptr.rs b/src/unique_ptr.rs
index 836f467..63a1ca7 100644
--- a/src/unique_ptr.rs
+++ b/src/unique_ptr.rs
@@ -6,10 +6,9 @@
 use core::ffi::c_void;
 use core::fmt::{self, Debug, Display};
 use core::marker::PhantomData;
-use core::mem;
+use core::mem::{self, MaybeUninit};
 use core::ops::{Deref, DerefMut};
 use core::pin::Pin;
-use core::ptr;
 
 /// Binding to C++ `std::unique_ptr<T, std::default_delete<T>>`.
 #[repr(C)]
@@ -17,7 +16,7 @@
 where
     T: UniquePtrTarget,
 {
-    repr: *mut c_void,
+    repr: MaybeUninit<*mut c_void>,
     ty: PhantomData<T>,
 }
 
@@ -104,7 +103,7 @@
     /// twice on the same raw pointer.
     pub unsafe fn from_raw(raw: *mut T) -> Self {
         UniquePtr {
-            repr: T::__raw(raw),
+            repr: unsafe { T::__raw(raw) },
             ty: PhantomData,
         }
     }
@@ -207,9 +206,9 @@
     #[doc(hidden)]
     fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
     #[doc(hidden)]
-    fn __null() -> *mut c_void;
+    fn __null() -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
-    fn __new(value: Self) -> *mut c_void
+    fn __new(value: Self) -> MaybeUninit<*mut c_void>
     where
         Self: Sized,
     {
@@ -219,26 +218,26 @@
         unreachable!()
     }
     #[doc(hidden)]
-    unsafe fn __raw(raw: *mut Self) -> *mut c_void;
+    unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
-    unsafe fn __get(repr: *mut c_void) -> *const Self;
+    unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self;
     #[doc(hidden)]
-    unsafe fn __release(repr: *mut c_void) -> *mut Self;
+    unsafe fn __release(repr: MaybeUninit<*mut c_void>) -> *mut Self;
     #[doc(hidden)]
-    unsafe fn __drop(repr: *mut c_void);
+    unsafe fn __drop(repr: MaybeUninit<*mut c_void>);
 }
 
 extern "C" {
     #[link_name = "cxxbridge1$unique_ptr$std$string$null"]
-    fn unique_ptr_std_string_null(this: *mut *mut c_void);
+    fn unique_ptr_std_string_null(this: *mut MaybeUninit<*mut c_void>);
     #[link_name = "cxxbridge1$unique_ptr$std$string$raw"]
-    fn unique_ptr_std_string_raw(this: *mut *mut c_void, raw: *mut CxxString);
+    fn unique_ptr_std_string_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxString);
     #[link_name = "cxxbridge1$unique_ptr$std$string$get"]
-    fn unique_ptr_std_string_get(this: *const *mut c_void) -> *const CxxString;
+    fn unique_ptr_std_string_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxString;
     #[link_name = "cxxbridge1$unique_ptr$std$string$release"]
-    fn unique_ptr_std_string_release(this: *mut *mut c_void) -> *mut CxxString;
+    fn unique_ptr_std_string_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxString;
     #[link_name = "cxxbridge1$unique_ptr$std$string$drop"]
-    fn unique_ptr_std_string_drop(this: *mut *mut c_void);
+    fn unique_ptr_std_string_drop(this: *mut MaybeUninit<*mut c_void>);
 }
 
 unsafe impl UniquePtrTarget for CxxString {
@@ -247,30 +246,30 @@
         f.write_str("CxxString")
     }
     #[doc(hidden)]
-    fn __null() -> *mut c_void {
-        let mut repr = ptr::null_mut::<c_void>();
+    fn __null() -> MaybeUninit<*mut c_void> {
+        let mut repr = MaybeUninit::uninit();
         unsafe {
             unique_ptr_std_string_null(&mut repr);
         }
         repr
     }
     #[doc(hidden)]
-    unsafe fn __raw(raw: *mut Self) -> *mut c_void {
-        let mut repr = ptr::null_mut::<c_void>();
-        unique_ptr_std_string_raw(&mut repr, raw);
+    unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void> {
+        let mut repr = MaybeUninit::uninit();
+        unsafe { unique_ptr_std_string_raw(&mut repr, raw) }
         repr
     }
     #[doc(hidden)]
-    unsafe fn __get(repr: *mut c_void) -> *const Self {
-        unique_ptr_std_string_get(&repr)
+    unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self {
+        unsafe { unique_ptr_std_string_get(&repr) }
     }
     #[doc(hidden)]
-    unsafe fn __release(mut repr: *mut c_void) -> *mut Self {
-        unique_ptr_std_string_release(&mut repr)
+    unsafe fn __release(mut repr: MaybeUninit<*mut c_void>) -> *mut Self {
+        unsafe { unique_ptr_std_string_release(&mut repr) }
     }
     #[doc(hidden)]
-    unsafe fn __drop(mut repr: *mut c_void) {
-        unique_ptr_std_string_drop(&mut repr);
+    unsafe fn __drop(mut repr: MaybeUninit<*mut c_void>) {
+        unsafe { unique_ptr_std_string_drop(&mut repr) }
     }
 }
 
@@ -283,23 +282,23 @@
         write!(f, "CxxVector<{}>", display(T::__typename))
     }
     #[doc(hidden)]
-    fn __null() -> *mut c_void {
+    fn __null() -> MaybeUninit<*mut c_void> {
         T::__unique_ptr_null()
     }
     #[doc(hidden)]
-    unsafe fn __raw(raw: *mut Self) -> *mut c_void {
-        T::__unique_ptr_raw(raw)
+    unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void> {
+        unsafe { T::__unique_ptr_raw(raw) }
     }
     #[doc(hidden)]
-    unsafe fn __get(repr: *mut c_void) -> *const Self {
-        T::__unique_ptr_get(repr)
+    unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self {
+        unsafe { T::__unique_ptr_get(repr) }
     }
     #[doc(hidden)]
-    unsafe fn __release(repr: *mut c_void) -> *mut Self {
-        T::__unique_ptr_release(repr)
+    unsafe fn __release(repr: MaybeUninit<*mut c_void>) -> *mut Self {
+        unsafe { T::__unique_ptr_release(repr) }
     }
     #[doc(hidden)]
-    unsafe fn __drop(repr: *mut c_void) {
-        T::__unique_ptr_drop(repr);
+    unsafe fn __drop(repr: MaybeUninit<*mut c_void>) {
+        unsafe { T::__unique_ptr_drop(repr) }
     }
 }
diff --git a/src/unwind.rs b/src/unwind.rs
index 36f6ae3..4967a21 100644
--- a/src/unwind.rs
+++ b/src/unwind.rs
@@ -1,3 +1,5 @@
+#![allow(missing_docs)]
+
 use std::io::{self, Write};
 use std::panic::{self, AssertUnwindSafe};
 use std::process;
diff --git a/src/weak_ptr.rs b/src/weak_ptr.rs
index 8291d59..8a9f1a6 100644
--- a/src/weak_ptr.rs
+++ b/src/weak_ptr.rs
@@ -16,7 +16,7 @@
 where
     T: WeakPtrTarget,
 {
-    repr: [*mut c_void; 2],
+    repr: [MaybeUninit<*mut c_void>; 2],
     ty: PhantomData<T>,
 }
 
@@ -91,8 +91,11 @@
     }
 }
 
-// Methods are private; not intended to be implemented outside of cxxbridge
-// codebase.
+/// Trait bound for types which may be used as the `T` inside of a `WeakPtr<T>`
+/// in generic code.
+///
+/// This trait has no publicly callable or implementable methods. Implementing
+/// it outside of the CXX codebase is not supported.
 pub unsafe trait WeakPtrTarget {
     #[doc(hidden)]
     fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
@@ -123,7 +126,7 @@
                         fn __null(new: *mut c_void);
                     }
                 }
-                __null(new);
+                unsafe { __null(new) }
             }
             #[doc(hidden)]
             unsafe fn __clone(this: *const c_void, new: *mut c_void) {
@@ -133,7 +136,7 @@
                         fn __clone(this: *const c_void, new: *mut c_void);
                     }
                 }
-                __clone(this, new);
+                unsafe { __clone(this, new) }
             }
             #[doc(hidden)]
             unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
@@ -143,7 +146,7 @@
                         fn __downgrade(shared: *const c_void, weak: *mut c_void);
                     }
                 }
-                __downgrade(shared, weak);
+                unsafe { __downgrade(shared, weak) }
             }
             #[doc(hidden)]
             unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
@@ -153,7 +156,7 @@
                         fn __upgrade(weak: *const c_void, shared: *mut c_void);
                     }
                 }
-                __upgrade(weak, shared);
+                unsafe { __upgrade(weak, shared) }
             }
             #[doc(hidden)]
             unsafe fn __drop(this: *mut c_void) {
@@ -163,7 +166,7 @@
                         fn __drop(this: *mut c_void);
                     }
                 }
-                __drop(this);
+                unsafe { __drop(this) }
             }
         }
     };
diff --git a/syntax/attrs.rs b/syntax/attrs.rs
index 4808f2e..fa6c809 100644
--- a/syntax/attrs.rs
+++ b/syntax/attrs.rs
@@ -4,7 +4,7 @@
 use crate::syntax::{Derive, Doc, ForeignName};
 use proc_macro2::{Ident, TokenStream};
 use quote::ToTokens;
-use syn::parse::{ParseStream, Parser as _};
+use syn::parse::{Nothing, Parse, ParseStream, Parser as _};
 use syn::{Attribute, Error, LitStr, Path, Result, Token};
 
 // Intended usage:
@@ -33,6 +33,7 @@
     pub namespace: Option<&'a mut Namespace>,
     pub cxx_name: Option<&'a mut Option<ForeignName>>,
     pub rust_name: Option<&'a mut Option<Ident>>,
+    pub variants_from_header: Option<&'a mut Option<Attribute>>,
 
     // Suppress clippy needless_update lint ("struct update has no effect, all
     // the fields in the struct have already been specified") when preemptively
@@ -121,6 +122,14 @@
                     break;
                 }
             }
+        } else if attr.path.is_ident("variants_from_header") && cfg!(feature = "experimental") {
+            if let Err(err) = Nothing::parse.parse2(attr.tokens.clone()) {
+                cx.push(err);
+            }
+            if let Some(variants_from_header) = &mut parser.variants_from_header {
+                **variants_from_header = Some(attr);
+                continue;
+            }
         } else if attr.path.is_ident("allow")
             || attr.path.is_ident("warn")
             || attr.path.is_ident("deny")
@@ -224,7 +233,19 @@
 impl ToTokens for OtherAttrs {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         for attr in &self.0 {
-            attr.to_tokens(tokens);
+            let Attribute {
+                pound_token,
+                style,
+                bracket_token,
+                path,
+                tokens: attr_tokens,
+            } = attr;
+            pound_token.to_tokens(tokens);
+            let _ = style; // ignore; render outer and inner attrs both as outer
+            bracket_token.surround(tokens, |tokens| {
+                path.to_tokens(tokens);
+                attr_tokens.to_tokens(tokens);
+            });
         }
     }
 }
diff --git a/syntax/check.rs b/syntax/check.rs
index bab2dec..698782f 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -2,24 +2,40 @@
 use crate::syntax::report::Errors;
 use crate::syntax::visit::{self, Visit};
 use crate::syntax::{
-    error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, NamedType, Ptr,
-    Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types,
+    error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, Lifetimes,
+    NamedType, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types,
 };
 use proc_macro2::{Delimiter, Group, Ident, TokenStream};
 use quote::{quote, ToTokens};
 use std::fmt::Display;
+use syn::{GenericParam, Generics, Lifetime};
 
 pub(crate) struct Check<'a> {
     apis: &'a [Api],
     types: &'a Types<'a>,
     errors: &'a mut Errors,
+    generator: Generator,
 }
 
-pub(crate) fn typecheck(cx: &mut Errors, apis: &[Api], types: &Types) {
+pub(crate) enum Generator {
+    // cxx-build crate, cxxbridge cli, cxx-gen.
+    #[allow(dead_code)]
+    Build,
+    // cxxbridge-macro. This is relevant in that the macro output is going to
+    // get fed straight to rustc, so for errors that rustc already contains
+    // logic to catch (probably with a better diagnostic than what the proc
+    // macro API is able to produce), we avoid duplicating them in our own
+    // diagnostics.
+    #[allow(dead_code)]
+    Macro,
+}
+
+pub(crate) fn typecheck(cx: &mut Errors, apis: &[Api], types: &Types, generator: Generator) {
     do_typecheck(&mut Check {
         apis,
         types,
         errors: cx,
+        generator,
     });
 }
 
@@ -250,7 +266,9 @@
 fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
     let supported = !is_unsized(cx, &ty.inner)
         || match &ty.inner {
-            Type::Ident(ident) => cx.types.rust.contains(&ident.rust),
+            Type::Ident(ident) => {
+                cx.types.rust.contains(&ident.rust) || cx.types.aliases.contains_key(&ident.rust)
+            }
             _ => false,
         };
 
@@ -294,6 +312,7 @@
 fn check_api_struct(cx: &mut Check, strct: &Struct) {
     let name = &strct.name;
     check_reserved_name(cx, &name.rust);
+    check_lifetimes(cx, &strct.generics);
 
     if strct.fields.is_empty() {
         let span = span_for_struct_error(strct);
@@ -330,8 +349,9 @@
 
 fn check_api_enum(cx: &mut Check, enm: &Enum) {
     check_reserved_name(cx, &enm.name.rust);
+    check_lifetimes(cx, &enm.generics);
 
-    if enm.variants.is_empty() && !enm.explicit_repr {
+    if enm.variants.is_empty() && !enm.explicit_repr && !enm.variants_from_header {
         let span = span_for_enum_error(enm);
         cx.error(
             span,
@@ -349,6 +369,7 @@
 
 fn check_api_type(cx: &mut Check, ety: &ExternType) {
     check_reserved_name(cx, &ety.name.rust);
+    check_lifetimes(cx, &ety.generics);
 
     for derive in &ety.derives {
         if derive.what == Trait::ExternType && ety.lang == Lang::Rust {
@@ -400,6 +421,8 @@
         }
     }
 
+    check_generics(cx, &efn.sig.generics);
+
     if let Some(receiver) = &efn.receiver {
         let ref span = span_for_receiver_error(receiver);
 
@@ -472,6 +495,8 @@
 }
 
 fn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) {
+    check_lifetimes(cx, &alias.generics);
+
     for derive in &alias.derives {
         let msg = format!("derive({}) on extern type alias is not supported", derive);
         cx.error(derive, msg);
@@ -481,6 +506,8 @@
 fn check_api_impl(cx: &mut Check, imp: &Impl) {
     let ty = &imp.ty;
 
+    check_lifetimes(cx, &imp.impl_generics);
+
     if let Some(negative) = imp.negative_token {
         let span = quote!(#negative #ty);
         cx.error(span, "negative impl is not supported yet");
@@ -583,6 +610,31 @@
     }
 }
 
+fn check_reserved_lifetime(cx: &mut Check, lifetime: &Lifetime) {
+    if lifetime.ident == "static" {
+        match cx.generator {
+            Generator::Macro => { /* rustc already reports this */ }
+            Generator::Build => {
+                cx.error(lifetime, error::RESERVED_LIFETIME);
+            }
+        }
+    }
+}
+
+fn check_lifetimes(cx: &mut Check, generics: &Lifetimes) {
+    for lifetime in &generics.lifetimes {
+        check_reserved_lifetime(cx, lifetime);
+    }
+}
+
+fn check_generics(cx: &mut Check, generics: &Generics) {
+    for generic_param in &generics.params {
+        if let GenericParam::Lifetime(def) = generic_param {
+            check_reserved_lifetime(cx, &def.lifetime);
+        }
+    }
+}
+
 fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
     match ty {
         Type::Ident(ident) => {
diff --git a/syntax/discriminant.rs b/syntax/discriminant.rs
index 80f7c0b..fff8f75 100644
--- a/syntax/discriminant.rs
+++ b/syntax/discriminant.rs
@@ -150,7 +150,7 @@
 }
 
 impl Discriminant {
-    const fn zero() -> Self {
+    pub const fn zero() -> Self {
         Discriminant {
             sign: Sign::Positive,
             magnitude: 0,
@@ -179,6 +179,28 @@
             magnitude: i.wrapping_abs() as u64,
         }
     }
+
+    pub const fn checked_succ(self) -> Option<Self> {
+        match self.sign {
+            Sign::Negative => {
+                if self.magnitude == 1 {
+                    Some(Discriminant::zero())
+                } else {
+                    Some(Discriminant {
+                        sign: Sign::Negative,
+                        magnitude: self.magnitude - 1,
+                    })
+                }
+            }
+            Sign::Positive => match self.magnitude.checked_add(1) {
+                Some(magnitude) => Some(Discriminant {
+                    sign: Sign::Positive,
+                    magnitude,
+                }),
+                None => None,
+            },
+        }
+    }
 }
 
 impl Display for Discriminant {
@@ -186,7 +208,7 @@
         if self.sign == Sign::Negative {
             f.write_str("-")?;
         }
-        Display::fmt(&self.magnitude, f)
+        write!(f, "{}", self.magnitude)
     }
 }
 
diff --git a/syntax/doc.rs b/syntax/doc.rs
index 60bb4da..cd764fa 100644
--- a/syntax/doc.rs
+++ b/syntax/doc.rs
@@ -17,6 +17,10 @@
         self.fragments.push(lit);
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.fragments.is_empty()
+    }
+
     pub fn to_string(&self) -> String {
         let mut doc = String::new();
         for lit in &self.fragments {
diff --git a/syntax/error.rs b/syntax/error.rs
index a672329..f40c4a8 100644
--- a/syntax/error.rs
+++ b/syntax/error.rs
@@ -21,6 +21,7 @@
     DISCRIMINANT_OVERFLOW,
     DOT_INCLUDE,
     DOUBLE_UNDERSCORE,
+    RESERVED_LIFETIME,
     RUST_TYPE_BY_VALUE,
     UNSUPPORTED_TYPE,
     USE_NOT_ALLOWED,
@@ -68,6 +69,12 @@
     note: Some("identifiers containing double underscore are reserved in C++"),
 };
 
+pub static RESERVED_LIFETIME: Error = Error {
+    msg: "invalid lifetime parameter name: `'static`",
+    label: Some("'static is a reserved lifetime name"),
+    note: None,
+};
+
 pub static RUST_TYPE_BY_VALUE: Error = Error {
     msg: "opaque Rust type by value is not supported",
     label: None,
diff --git a/syntax/file.rs b/syntax/file.rs
index fd6dd98..99466b8 100644
--- a/syntax/file.rs
+++ b/syntax/file.rs
@@ -91,17 +91,32 @@
 
         let item = input.parse()?;
         match item {
-            RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })),
-            RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })),
-            RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod {
-                attrs,
-                unsafety,
-                abi: item.abi,
-                brace_token: item.brace_token,
-                items: item.items,
-            })),
-            RustItem::Impl(item) => Ok(Item::Impl(ItemImpl { attrs, ..item })),
-            RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
+            RustItem::Struct(mut item) => {
+                item.attrs.splice(..0, attrs);
+                Ok(Item::Struct(item))
+            }
+            RustItem::Enum(mut item) => {
+                item.attrs.splice(..0, attrs);
+                Ok(Item::Enum(item))
+            }
+            RustItem::ForeignMod(mut item) => {
+                item.attrs.splice(..0, attrs);
+                Ok(Item::ForeignMod(ItemForeignMod {
+                    attrs: item.attrs,
+                    unsafety,
+                    abi: item.abi,
+                    brace_token: item.brace_token,
+                    items: item.items,
+                }))
+            }
+            RustItem::Impl(mut item) => {
+                item.attrs.splice(..0, attrs);
+                Ok(Item::Impl(item))
+            }
+            RustItem::Use(mut item) => {
+                item.attrs.splice(..0, attrs);
+                Ok(Item::Use(item))
+            }
             other => Ok(Item::Other(other)),
         }
     }
diff --git a/syntax/impls.rs b/syntax/impls.rs
index 8b0743b..06d68dc 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -339,6 +339,7 @@
                     attrs: _,
                     visibility: _,
                     name: _,
+                    colon_token: _,
                     ty,
                 } = arg;
                 let Var {
@@ -346,6 +347,7 @@
                     attrs: _,
                     visibility: _,
                     name: _,
+                    colon_token: _,
                     ty: ty2,
                 } = arg2;
                 ty == ty2
@@ -374,6 +376,7 @@
                 attrs: _,
                 visibility: _,
                 name: _,
+                colon_token: _,
                 ty,
             } = arg;
             ty.hash(state);
@@ -393,6 +396,7 @@
             lifetime,
             mutable,
             var: _,
+            colon_token: _,
             ty,
             shorthand: _,
             pin_tokens: _,
@@ -404,6 +408,7 @@
             lifetime: lifetime2,
             mutable: mutable2,
             var: _,
+            colon_token: _,
             ty: ty2,
             shorthand: _,
             pin_tokens: _,
@@ -421,6 +426,7 @@
             lifetime,
             mutable,
             var: _,
+            colon_token: _,
             ty,
             shorthand: _,
             pin_tokens: _,
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 3d56293..1d98634 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -30,17 +30,17 @@
 mod visit;
 
 use self::attrs::OtherAttrs;
-use self::discriminant::Discriminant;
 use self::namespace::Namespace;
 use self::parse::kw;
 use self::symbol::Symbol;
 use proc_macro2::{Ident, Span};
 use syn::punctuated::Punctuated;
 use syn::token::{Brace, Bracket, Paren};
-use syn::{Expr, Generics, Lifetime, LitInt, Token, Type as RustType};
+use syn::{Attribute, Expr, Generics, Lifetime, LitInt, Path, Token, Type as RustType};
 
 pub use self::atom::Atom;
 pub use self::derive::{Derive, Trait};
+pub use self::discriminant::Discriminant;
 pub use self::doc::Doc;
 pub use self::names::ForeignName;
 pub use self::parse::parse_items;
@@ -111,11 +111,17 @@
     pub generics: Lifetimes,
     pub brace_token: Brace,
     pub variants: Vec<Variant>,
-    pub repr: Atom,
-    pub repr_type: Type,
+    pub variants_from_header: bool,
+    pub variants_from_header_attr: Option<Attribute>,
+    pub repr: EnumRepr,
     pub explicit_repr: bool,
 }
 
+pub enum EnumRepr {
+    Native { atom: Atom, repr_type: Type },
+    Foreign { rust_type: Path },
+}
+
 pub struct ExternFn {
     pub lang: Lang,
     pub doc: Doc,
@@ -174,6 +180,7 @@
     pub attrs: OtherAttrs,
     pub visibility: Token![pub],
     pub name: Pair,
+    pub colon_token: Token![:],
     pub ty: Type,
 }
 
@@ -184,6 +191,7 @@
     pub mutable: bool,
     pub var: Token![self],
     pub ty: NamedType,
+    pub colon_token: Token![:],
     pub shorthand: bool,
     pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
     pub mutability: Option<Token![mut]>,
diff --git a/syntax/names.rs b/syntax/names.rs
index cb6ace5..7a125ae 100644
--- a/syntax/names.rs
+++ b/syntax/names.rs
@@ -9,7 +9,6 @@
 #[derive(Clone)]
 pub struct ForeignName {
     text: String,
-    span: Span,
 }
 
 impl Pair {
@@ -56,7 +55,7 @@
         match syn::parse_str::<Ident>(text) {
             Ok(ident) => {
                 let text = ident.to_string();
-                Ok(ForeignName { text, span })
+                Ok(ForeignName { text })
             }
             Err(err) => Err(Error::new(span, err)),
         }
@@ -68,3 +67,9 @@
         formatter.write_str(&self.text)
     }
 }
+
+impl PartialEq<str> for ForeignName {
+    fn eq(&self, rhs: &str) -> bool {
+        self.text == rhs
+    }
+}
diff --git a/syntax/parse.rs b/syntax/parse.rs
index d792076..32d36eb 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -4,9 +4,9 @@
 use crate::syntax::report::Errors;
 use crate::syntax::Atom::*;
 use crate::syntax::{
-    attrs, error, Api, Array, Derive, Doc, Enum, ExternFn, ExternType, ForeignName, Impl, Include,
-    IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Ptr, Receiver, Ref, Signature,
-    SliceRef, Struct, Ty1, Type, TypeAlias, Var, Variant,
+    attrs, error, Api, Array, Derive, Doc, Enum, EnumRepr, ExternFn, ExternType, ForeignName, Impl,
+    Include, IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Ptr, Receiver, Ref,
+    Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var, Variant,
 };
 use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
 use quote::{format_ident, quote, quote_spanned};
@@ -146,11 +146,13 @@
         };
         let visibility = visibility_pub(&field.vis, ident.span());
         let name = pair(Namespace::default(), &ident, cxx_name, rust_name);
+        let colon_token = field.colon_token.unwrap();
         fields.push(Var {
             doc,
             attrs,
             visibility,
             name,
+            colon_token,
             ty,
         });
     }
@@ -185,6 +187,7 @@
     let mut namespace = namespace.clone();
     let mut cxx_name = None;
     let mut rust_name = None;
+    let mut variants_from_header = None;
     let attrs = attrs::parse(
         cx,
         item.attrs,
@@ -195,6 +198,7 @@
             namespace: Some(&mut namespace),
             cxx_name: Some(&mut cxx_name),
             rust_name: Some(&mut rust_name),
+            variants_from_header: Some(&mut variants_from_header),
             ..Default::default()
         },
     );
@@ -237,11 +241,17 @@
     let name = pair(namespace, &item.ident, cxx_name, rust_name);
     let repr_ident = Ident::new(repr.as_ref(), Span::call_site());
     let repr_type = Type::Ident(NamedType::new(repr_ident));
+    let repr = EnumRepr::Native {
+        atom: repr,
+        repr_type,
+    };
     let generics = Lifetimes {
         lt_token: None,
         lifetimes: Punctuated::new(),
         gt_token: None,
     };
+    let variants_from_header_attr = variants_from_header;
+    let variants_from_header = variants_from_header_attr.is_some();
 
     Api::Enum(Enum {
         doc,
@@ -253,8 +263,9 @@
         generics,
         brace_token,
         variants,
+        variants_from_header,
+        variants_from_header_attr,
         repr,
-        repr_type,
         explicit_repr,
     })
 }
@@ -560,6 +571,7 @@
                         lifetime: lifetime.clone(),
                         mutable: arg.mutability.is_some(),
                         var: arg.self_token,
+                        colon_token: Token![:](arg.self_token.span),
                         ty: NamedType::new(Ident::new("Self", arg.self_token.span)),
                         shorthand: true,
                         pin_tokens: None,
@@ -583,11 +595,13 @@
                     let attrs = OtherAttrs::none();
                     let visibility = Token![pub](ident.span());
                     let name = pair(Namespace::default(), &ident, None, None);
+                    let colon_token = arg.colon_token;
                     args.push_value(Var {
                         doc,
                         attrs,
                         visibility,
                         name,
+                        colon_token,
                         ty,
                     });
                     if let Some(comma) = comma {
@@ -603,6 +617,7 @@
                             lifetime: reference.lifetime,
                             mutable: reference.mutable,
                             var: Token![self](ident.rust.span()),
+                            colon_token: arg.colon_token,
                             ty: ident,
                             shorthand: false,
                             pin_tokens: reference.pin_tokens,
@@ -1272,11 +1287,16 @@
         .iter()
         .enumerate()
         .map(|(i, arg)| {
-            let ty = parse_type(&arg.ty)?;
-            let ident = match &arg.name {
-                Some(ident) => ident.0.clone(),
-                None => format_ident!("arg{}", i),
+            let (ident, colon_token) = match &arg.name {
+                Some((ident, colon_token)) => (ident.clone(), *colon_token),
+                None => {
+                    let fn_span = ty.paren_token.span;
+                    let ident = format_ident!("arg{}", i, span = fn_span);
+                    let colon_token = Token![:](fn_span);
+                    (ident, colon_token)
+                }
             };
+            let ty = parse_type(&arg.ty)?;
             let doc = Doc::new();
             let attrs = OtherAttrs::none();
             let visibility = Token![pub](ident.span());
@@ -1286,6 +1306,7 @@
                 attrs,
                 visibility,
                 name,
+                colon_token,
                 ty,
             })
         })
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index c1a06a2..33f20fa 100644
--- a/syntax/tokens.rs
+++ b/syntax/tokens.rs
@@ -1,7 +1,7 @@
 use crate::syntax::atom::Atom::*;
 use crate::syntax::{
-    Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Lifetimes, NamedType, Ptr, Receiver,
-    Ref, Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
+    Array, Atom, Derive, Enum, EnumRepr, ExternFn, ExternType, Impl, Lifetimes, NamedType, Ptr,
+    Receiver, Ref, Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{quote_spanned, ToTokens};
@@ -43,6 +43,7 @@
             attrs: _,
             visibility: _,
             name,
+            colon_token: _,
             ty,
         } = self;
         name.rust.to_tokens(tokens);
@@ -279,6 +280,15 @@
     }
 }
 
+impl ToTokens for EnumRepr {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        match self {
+            EnumRepr::Native { atom, repr_type: _ } => atom.to_tokens(tokens),
+            EnumRepr::Foreign { rust_type } => rust_type.to_tokens(tokens),
+        }
+    }
+}
+
 impl ToTokens for NamedType {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         let NamedType { rust, generics } = self;
@@ -310,6 +320,7 @@
             lifetime,
             mutable: _,
             var: _,
+            colon_token: _,
             ty,
             shorthand: _,
             pin_tokens,
@@ -337,6 +348,7 @@
             lifetime,
             mutable: _,
             var: _,
+            colon_token: _,
             ty,
             shorthand: _,
             pin_tokens,
diff --git a/syntax/trivial.rs b/syntax/trivial.rs
index fe95e2b..067e2d7 100644
--- a/syntax/trivial.rs
+++ b/syntax/trivial.rs
@@ -11,6 +11,7 @@
     FunctionReturn(&'a ExternFn),
     BoxTarget,
     VecElement,
+    SliceElement { mutable: bool },
     UnpinnedMut(&'a ExternFn),
 }
 
@@ -105,6 +106,14 @@
                     insist_extern_types_are_trivial(ident, reason);
                 }
             }
+            Type::SliceRef(ty) => {
+                if let Type::Ident(ident) = &ty.inner {
+                    let reason = TrivialReason::SliceElement {
+                        mutable: ty.mutable,
+                    };
+                    insist_extern_types_are_trivial(ident, reason);
+                }
+            }
             _ => {}
         }
     }
@@ -128,6 +137,8 @@
             let mut return_of = Set::new();
             let mut box_target = false;
             let mut vec_element = false;
+            let mut slice_shared_element = false;
+            let mut slice_mut_element = false;
             let mut unpinned_mut = Set::new();
 
             for reason in self.reasons {
@@ -143,6 +154,13 @@
                     }
                     TrivialReason::BoxTarget => box_target = true,
                     TrivialReason::VecElement => vec_element = true,
+                    TrivialReason::SliceElement { mutable } => {
+                        if *mutable {
+                            slice_mut_element = true;
+                        } else {
+                            slice_shared_element = true;
+                        }
+                    }
                     TrivialReason::UnpinnedMut(efn) => {
                         unpinned_mut.insert(&efn.name.rust);
                     }
@@ -185,6 +203,15 @@
                     param: self.name,
                 });
             }
+            if slice_shared_element || slice_mut_element {
+                clauses.push(Clause::Slice {
+                    article: "a",
+                    desc: "slice element in",
+                    shared: slice_shared_element,
+                    mutable: slice_mut_element,
+                    param: self.name,
+                });
+            }
             if !unpinned_mut.is_empty() {
                 clauses.push(Clause::Set {
                     article: "a",
@@ -219,12 +246,21 @@
             desc: &'a str,
             param: &'a Pair,
         },
+        Slice {
+            article: &'a str,
+            desc: &'a str,
+            shared: bool,
+            mutable: bool,
+            param: &'a Pair,
+        },
     }
 
     impl<'a> Clause<'a> {
         fn article(&self) -> &'a str {
             match self {
-                Clause::Set { article, .. } | Clause::Ty1 { article, .. } => article,
+                Clause::Set { article, .. }
+                | Clause::Ty1 { article, .. }
+                | Clause::Slice { article, .. } => article,
             }
         }
 
@@ -249,6 +285,25 @@
                     desc,
                     param,
                 } => write!(f, "{}<{}>", desc, param.rust),
+                Clause::Slice {
+                    article: _,
+                    desc,
+                    shared,
+                    mutable,
+                    param,
+                } => {
+                    write!(f, "{} ", desc)?;
+                    if *shared {
+                        write!(f, "&[{}]", param.rust)?;
+                    }
+                    if *shared && *mutable {
+                        write!(f, " and ")?;
+                    }
+                    if *mutable {
+                        write!(f, "&mut [{}]", param.rust)?;
+                    }
+                    Ok(())
+                }
             }
         }
     }
diff --git a/syntax/types.rs b/syntax/types.rs
index af7916d..c54682b 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -7,7 +7,7 @@
 use crate::syntax::trivial::{self, TrivialReason};
 use crate::syntax::visit::{self, Visit};
 use crate::syntax::{
-    toposort, Api, Atom, Enum, ExternType, Impl, Lifetimes, Pair, Struct, Type, TypeAlias,
+    toposort, Api, Atom, Enum, EnumRepr, ExternType, Impl, Lifetimes, Pair, Struct, Type, TypeAlias,
 };
 use proc_macro2::Ident;
 use quote::ToTokens;
@@ -88,7 +88,12 @@
                     add_resolution(&strct.name, &strct.generics);
                 }
                 Api::Enum(enm) => {
-                    all.insert(&enm.repr_type);
+                    match &enm.repr {
+                        EnumRepr::Native { atom: _, repr_type } => {
+                            all.insert(repr_type);
+                        }
+                        EnumRepr::Foreign { rust_type: _ } => {}
+                    }
                     let ident = &enm.name.rust;
                     if !type_names.insert(ident)
                         && (!cxx.contains(ident)
@@ -101,6 +106,11 @@
                         duplicate_name(cx, enm, ident);
                     }
                     enums.insert(ident, enm);
+                    if enm.variants_from_header {
+                        // #![variants_from_header] enums are implicitly extern
+                        // C++ type.
+                        cxx.insert(&enm.name.rust);
+                    }
                     add_resolution(&enm.name, &enm.generics);
                 }
                 Api::CxxType(ety) => {
@@ -250,6 +260,14 @@
             ImproperCtype::Depends(ident) => self.struct_improper_ctypes.contains(ident),
         }
     }
+
+    // Types which we need to assume could possibly exist by value on the Rust
+    // side.
+    pub fn is_maybe_trivial(&self, ty: &Ident) -> bool {
+        self.structs.contains_key(ty)
+            || self.enums.contains_key(ty)
+            || self.aliases.contains_key(ty)
+    }
 }
 
 impl<'t, 'a> IntoIterator for &'t Types<'a> {
diff --git a/tests/BUILD b/tests/BUILD
index 7886e4f..d4af3af 100644
--- a/tests/BUILD
+++ b/tests/BUILD
@@ -1,5 +1,5 @@
 load("@rules_cc//cc:defs.bzl", "cc_library")
-load("//tools/bazel:rust.bzl", "rust_library", "rust_test")
+load("@rules_rust//rust:rust.bzl", "rust_library", "rust_test")
 load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_test(
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index fcbe153..25b4ccd 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -157,6 +157,10 @@
         fn c_take_ref_rust_vec_copy(v: &Vec<u8>);
         fn c_take_ref_shared_string(s: &SharedString) -> &SharedString;
         fn c_take_callback(callback: fn(String) -> usize);
+        fn c_take_callback_ref(callback: fn(&String));
+        #[cxx_name = "c_take_callback_ref"]
+        fn c_take_callback_ref_lifetime<'a>(callback: fn(&'a String));
+        fn c_take_callback_mut(callback: fn(&mut String));
         fn c_take_enum(e: Enum);
         fn c_take_ns_enum(e: AEnum);
         fn c_take_nested_ns_enum(e: ABEnum);
@@ -322,6 +326,7 @@
     }
 
     impl Box<Shared> {}
+    impl CxxVector<SharedString> {}
 }
 
 mod other {
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index ba12ed4..df7ded0 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -336,13 +336,13 @@
 }
 
 void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v) {
-  if (v->size() == 4) {
+  if (v->size() == 3) {
     cxx_test_suite_set_correct();
   }
 }
 
 void c_take_unique_ptr_vector_f64(std::unique_ptr<std::vector<double>> v) {
-  if (v->size() == 4) {
+  if (v->size() == 5) {
     cxx_test_suite_set_correct();
   }
 }
@@ -354,7 +354,7 @@
 }
 
 void c_take_unique_ptr_vector_shared(std::unique_ptr<std::vector<Shared>> v) {
-  if (v->size() == 2) {
+  if (v->size() == 3) {
     cxx_test_suite_set_correct();
   }
 }
@@ -494,6 +494,16 @@
   callback("2020");
 }
 
+void c_take_callback_ref(rust::Fn<void(const rust::String &)> callback) {
+  const rust::String string = "2020";
+  callback(string);
+}
+
+void c_take_callback_mut(rust::Fn<void(rust::String &)> callback) {
+  rust::String string = "2020";
+  callback(string);
+}
+
 void c_take_enum(Enum e) {
   if (e == Enum::AVal) {
     cxx_test_suite_set_correct();
@@ -825,12 +835,24 @@
   ASSERT(cstring == "foo");
   ASSERT(other_cstring == "test");
 
+  ASSERT(cstring.capacity() == 3);
+  cstring.reserve(2);
+  ASSERT(cstring.capacity() == 3);
+  cstring.reserve(5);
+  ASSERT(cstring.capacity() >= 5);
+
   rust::Str cstr = "test";
   rust::Str other_cstr = "foo";
   swap(cstr, other_cstr);
   ASSERT(cstr == "foo");
   ASSERT(other_cstr == "test");
 
+  const char *utf8_literal = u8"Test string";
+  const char16_t *utf16_literal = u"Test string";
+  rust::String utf8_rstring = utf8_literal;
+  rust::String utf16_rstring = utf16_literal;
+  ASSERT(utf8_rstring == utf16_rstring);
+
   rust::Vec<int> vec1{1, 2};
   rust::Vec<int> vec2{3, 4};
   swap(vec1, vec2);
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index 74acbf4..b624d39 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -160,6 +160,8 @@
 void c_take_ref_rust_vec_copy(const rust::Vec<uint8_t> &v);
 const SharedString &c_take_ref_shared_string(const SharedString &s);
 void c_take_callback(rust::Fn<size_t(rust::String)> callback);
+void c_take_callback_ref(rust::Fn<void(const rust::String &)> callback);
+void c_take_callback_mut(rust::Fn<void(rust::String &)> callback);
 void c_take_enum(Enum e);
 void c_take_ns_enum(::A::AEnum e);
 void c_take_nested_ns_enum(::A::B::ABEnum e);
diff --git a/tests/test.rs b/tests/test.rs
index 32b8e83..1f0b166 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -150,15 +150,15 @@
     check!(ffi::c_take_unique_ptr_string(
         ffi::c_return_unique_ptr_string()
     ));
-    check!(ffi::c_take_unique_ptr_vector_u8(
-        ffi::c_return_unique_ptr_vector_u8()
-    ));
-    check!(ffi::c_take_unique_ptr_vector_f64(
-        ffi::c_return_unique_ptr_vector_f64()
-    ));
-    check!(ffi::c_take_unique_ptr_vector_shared(
-        ffi::c_return_unique_ptr_vector_shared()
-    ));
+    let mut vector = ffi::c_return_unique_ptr_vector_u8();
+    assert_eq!(vector.pin_mut().pop(), Some(9));
+    check!(ffi::c_take_unique_ptr_vector_u8(vector));
+    let mut vector = ffi::c_return_unique_ptr_vector_f64();
+    vector.pin_mut().push(9.0);
+    check!(ffi::c_take_unique_ptr_vector_f64(vector));
+    let mut vector = ffi::c_return_unique_ptr_vector_shared();
+    vector.pin_mut().push(ffi::Shared { z: 9 });
+    check!(ffi::c_take_unique_ptr_vector_shared(vector));
     check!(ffi::c_take_ref_vector(&ffi::c_return_unique_ptr_vector_u8()));
     let test_vec = [86_u8, 75_u8, 30_u8, 9_u8].to_vec();
     check!(ffi::c_take_rust_vec(test_vec.clone()));
@@ -204,7 +204,23 @@
         0
     }
 
+    #[allow(clippy::ptr_arg)]
+    fn callback_ref(s: &String) {
+        if s == "2020" {
+            cxx_test_suite_set_correct();
+        }
+    }
+
+    fn callback_mut(s: &mut String) {
+        if s == "2020" {
+            cxx_test_suite_set_correct();
+        }
+    }
+
     check!(ffi::c_take_callback(callback));
+    check!(ffi::c_take_callback_ref(callback_ref));
+    check!(ffi::c_take_callback_ref_lifetime(callback_ref));
+    check!(ffi::c_take_callback_mut(callback_mut));
 }
 
 #[test]
diff --git a/tests/ui/array_len_suffix.stderr b/tests/ui/array_len_suffix.stderr
index b72fc02..143bcb0 100644
--- a/tests/ui/array_len_suffix.stderr
+++ b/tests/ui/array_len_suffix.stderr
@@ -7,4 +7,4 @@
 help: change the type of the numeric literal from `u16` to `usize`
   |
 4 |         fn array() -> [String; 12usize];
-  |                                ^^^^^^^
+  |                                  ~~~~~
diff --git a/tests/ui/derive_nonclone.rs b/tests/ui/derive_nonclone.rs
deleted file mode 100644
index 5811028..0000000
--- a/tests/ui/derive_nonclone.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[cxx::bridge]
-mod ffi {
-    #[derive(Clone)]
-    struct TryClone {
-        other: Other,
-    }
-
-    struct Other {
-        x: usize,
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/derive_nonclone.stderr b/tests/ui/derive_nonclone.stderr
deleted file mode 100644
index 04eae4f..0000000
--- a/tests/ui/derive_nonclone.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error[E0277]: the trait bound `ffi::Other: Clone` is not satisfied
- --> $DIR/derive_nonclone.rs:5:9
-  |
-5 |         other: Other,
-  |         ^^^^^^^^^^^^ the trait `Clone` is not implemented for `ffi::Other`
-  |
-  = note: required by `clone`
diff --git a/tests/ui/expected_named.stderr b/tests/ui/expected_named.stderr
index 4676401..dab3b5a 100644
--- a/tests/ui/expected_named.stderr
+++ b/tests/ui/expected_named.stderr
@@ -8,4 +8,4 @@
 help: consider using the `'static` lifetime
   |
 5 |         fn borrowed() -> UniquePtr<Borrowed<'static>>;
-  |                                    ^^^^^^^^^^^^^^^^^
+  |                                    ~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/opaque_autotraits.stderr b/tests/ui/opaque_autotraits.stderr
index 4f469ef..15a2b64 100644
--- a/tests/ui/opaque_autotraits.stderr
+++ b/tests/ui/opaque_autotraits.stderr
@@ -1,40 +1,59 @@
-error[E0277]: `*const u8` cannot be sent between threads safely
+error[E0277]: `*const cxx::void` cannot be sent between threads safely
   --> $DIR/opaque_autotraits.rs:13:5
    |
-8  | fn assert_send<T: Send>() {}
-   |                   ---- required by this bound in `assert_send`
-...
 13 |     assert_send::<ffi::Opaque>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const cxx::void` cannot be sent between threads safely
    |
-   = help: within `ffi::Opaque`, the trait `Send` is not implemented for `*const u8`
-   = note: required because it appears within the type `[*const u8; 0]`
+   = help: within `ffi::Opaque`, the trait `Send` is not implemented for `*const cxx::void`
+   = note: required because it appears within the type `[*const cxx::void; 0]`
    = note: required because it appears within the type `cxx::private::Opaque`
-   = note: required because it appears within the type `ffi::Opaque`
+note: required because it appears within the type `ffi::Opaque`
+  --> $DIR/opaque_autotraits.rs:4:14
+   |
+4  |         type Opaque;
+   |              ^^^^^^
+note: required by a bound in `assert_send`
+  --> $DIR/opaque_autotraits.rs:8:19
+   |
+8  | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
 
-error[E0277]: `*const u8` cannot be shared between threads safely
+error[E0277]: `*const cxx::void` cannot be shared between threads safely
   --> $DIR/opaque_autotraits.rs:14:5
    |
-9  | fn assert_sync<T: Sync>() {}
-   |                   ---- required by this bound in `assert_sync`
-...
 14 |     assert_sync::<ffi::Opaque>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const u8` cannot be shared between threads safely
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const cxx::void` cannot be shared between threads safely
    |
-   = help: within `ffi::Opaque`, the trait `Sync` is not implemented for `*const u8`
-   = note: required because it appears within the type `[*const u8; 0]`
+   = help: within `ffi::Opaque`, the trait `Sync` is not implemented for `*const cxx::void`
+   = note: required because it appears within the type `[*const cxx::void; 0]`
    = note: required because it appears within the type `cxx::private::Opaque`
-   = note: required because it appears within the type `ffi::Opaque`
+note: required because it appears within the type `ffi::Opaque`
+  --> $DIR/opaque_autotraits.rs:4:14
+   |
+4  |         type Opaque;
+   |              ^^^^^^
+note: required by a bound in `assert_sync`
+  --> $DIR/opaque_autotraits.rs:9:19
+   |
+9  | fn assert_sync<T: Sync>() {}
+   |                   ^^^^ required by this bound in `assert_sync`
 
 error[E0277]: `PhantomPinned` cannot be unpinned
   --> $DIR/opaque_autotraits.rs:15:5
    |
-10 | fn assert_unpin<T: Unpin>() {}
-   |                    ----- required by this bound in `assert_unpin`
-...
 15 |     assert_unpin::<ffi::Opaque>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ffi::Opaque`, the trait `Unpin` is not implemented for `PhantomPinned`
    |
+   = note: consider using `Box::pin`
    = note: required because it appears within the type `PhantomData<PhantomPinned>`
    = note: required because it appears within the type `cxx::private::Opaque`
-   = note: required because it appears within the type `ffi::Opaque`
+note: required because it appears within the type `ffi::Opaque`
+  --> $DIR/opaque_autotraits.rs:4:14
+   |
+4  |         type Opaque;
+   |              ^^^^^^
+note: required by a bound in `assert_unpin`
+  --> $DIR/opaque_autotraits.rs:10:20
+   |
+10 | fn assert_unpin<T: Unpin>() {}
+   |                    ^^^^^ required by this bound in `assert_unpin`
diff --git a/tests/ui/opaque_not_sized.stderr b/tests/ui/opaque_not_sized.stderr
index 9818e44..b50a269 100644
--- a/tests/ui/opaque_not_sized.stderr
+++ b/tests/ui/opaque_not_sized.stderr
@@ -2,10 +2,16 @@
  --> $DIR/opaque_not_sized.rs:4:14
   |
 4 |         type TypeR;
-  |         -----^^^^^-
-  |         |    |
-  |         |    doesn't have a size known at compile-time
-  |         required by this bound in `__AssertSized`
+  |              ^^^^^ doesn't have a size known at compile-time
   |
   = help: within `TypeR`, the trait `Sized` is not implemented for `str`
-  = note: required because it appears within the type `TypeR`
+note: required because it appears within the type `TypeR`
+ --> $DIR/opaque_not_sized.rs:8:8
+  |
+8 | struct TypeR(str);
+  |        ^^^^^
+note: required by a bound in `__AssertSized`
+ --> $DIR/opaque_not_sized.rs:4:9
+  |
+4 |         type TypeR;
+  |         ^^^^^^^^^^^ required by this bound in `__AssertSized`
diff --git a/tests/ui/reserved_lifetime.rs b/tests/ui/reserved_lifetime.rs
new file mode 100644
index 0000000..179a4db
--- /dev/null
+++ b/tests/ui/reserved_lifetime.rs
@@ -0,0 +1,10 @@
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        type Logger;
+
+        fn logger<'static>() -> Pin<&'static Logger>;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/reserved_lifetime.stderr b/tests/ui/reserved_lifetime.stderr
new file mode 100644
index 0000000..723572d
--- /dev/null
+++ b/tests/ui/reserved_lifetime.stderr
@@ -0,0 +1,5 @@
+error[E0262]: invalid lifetime parameter name: `'static`
+ --> $DIR/reserved_lifetime.rs:6:19
+  |
+6 |         fn logger<'static>() -> Pin<&'static Logger>;
+  |                   ^^^^^^^ 'static is a reserved lifetime name
diff --git a/tests/ui/rust_pinned.stderr b/tests/ui/rust_pinned.stderr
index f16f9d5..8857681 100644
--- a/tests/ui/rust_pinned.stderr
+++ b/tests/ui/rust_pinned.stderr
@@ -1,10 +1,17 @@
 error[E0277]: `PhantomPinned` cannot be unpinned
- --> $DIR/rust_pinned.rs:6:14
-  |
-6 |         type Pinned;
-  |         -----^^^^^^-
-  |         |    |
-  |         |    within `Pinned`, the trait `Unpin` is not implemented for `PhantomPinned`
-  |         required by this bound in `__AssertUnpin`
-  |
-  = note: required because it appears within the type `Pinned`
+  --> $DIR/rust_pinned.rs:6:14
+   |
+6  |         type Pinned;
+   |              ^^^^^^ within `Pinned`, the trait `Unpin` is not implemented for `PhantomPinned`
+   |
+   = note: consider using `Box::pin`
+note: required because it appears within the type `Pinned`
+  --> $DIR/rust_pinned.rs:10:12
+   |
+10 | pub struct Pinned {
+   |            ^^^^^^
+note: required by a bound in `__AssertUnpin`
+  --> $DIR/rust_pinned.rs:6:9
+   |
+6  |         type Pinned;
+   |         ^^^^^^^^^^^^ required by this bound in `__AssertUnpin`
diff --git a/tests/ui/slice_of_type_alias.rs b/tests/ui/slice_of_type_alias.rs
new file mode 100644
index 0000000..a7bbc11
--- /dev/null
+++ b/tests/ui/slice_of_type_alias.rs
@@ -0,0 +1,30 @@
+use cxx::{type_id, ExternType};
+
+#[repr(C)]
+struct ElementTrivial(usize);
+
+#[repr(C)]
+struct ElementOpaque(usize);
+
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        type ElementTrivial = crate::ElementTrivial;
+        type ElementOpaque = crate::ElementOpaque;
+
+        fn f(slice: &mut [ElementTrivial]);
+        fn g(slice: &[ElementOpaque]);
+    }
+}
+
+unsafe impl ExternType for ElementTrivial {
+    type Id = type_id!("ElementTrivial");
+    type Kind = cxx::kind::Trivial;
+}
+
+unsafe impl ExternType for ElementOpaque {
+    type Id = type_id!("ElementOpaque");
+    type Kind = cxx::kind::Opaque;
+}
+
+fn main() {}
diff --git a/tests/ui/slice_of_type_alias.stderr b/tests/ui/slice_of_type_alias.stderr
new file mode 100644
index 0000000..aff06f8
--- /dev/null
+++ b/tests/ui/slice_of_type_alias.stderr
@@ -0,0 +1,11 @@
+error[E0271]: type mismatch resolving `<ElementOpaque as ExternType>::Kind == Trivial`
+   --> $DIR/slice_of_type_alias.rs:13:9
+    |
+13  |         type ElementOpaque = crate::ElementOpaque;
+    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque`
+    |
+note: required by a bound in `verify_extern_kind`
+   --> $DIR/extern_type.rs:186:41
+    |
+186 | pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
+    |                                         ^^^^^^^^^^^ required by this bound in `verify_extern_kind`
diff --git a/tests/ui/slice_unsupported.stderr b/tests/ui/slice_unsupported.stderr
index 787076f..2cbd26d 100644
--- a/tests/ui/slice_unsupported.stderr
+++ b/tests/ui/slice_unsupported.stderr
@@ -3,3 +3,9 @@
   |
 6 |         fn f(_: &mut [Opaque]);
   |                 ^^^^^^^^^^^^^
+
+error: needs a cxx::ExternType impl in order to be used as a slice element in &mut [Opaque]
+ --> $DIR/slice_unsupported.rs:4:9
+  |
+4 |         type Opaque;
+  |         ^^^^^^^^^^^
diff --git a/tests/ui/unique_ptr_to_opaque.stderr b/tests/ui/unique_ptr_to_opaque.stderr
index 19d76a3..28e45cf 100644
--- a/tests/ui/unique_ptr_to_opaque.stderr
+++ b/tests/ui/unique_ptr_to_opaque.stderr
@@ -4,4 +4,10 @@
 22 |     cxx::UniquePtr::new(outside::C { a: 4 });
    |     ^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque`
    |
-   = note: required by `UniquePtr::<T>::new`
+note: required by `UniquePtr::<T>::new`
+  --> $DIR/unique_ptr.rs:38:5
+   |
+38 | /     pub fn new(value: T) -> Self
+39 | |     where
+40 | |         T: ExternType<Kind = Trivial>,
+   | |______________________________________^
diff --git a/tests/ui/unsupported_elided.stderr b/tests/ui/unsupported_elided.stderr
index 932076d..8e8a986 100644
--- a/tests/ui/unsupported_elided.stderr
+++ b/tests/ui/unsupported_elided.stderr
@@ -3,6 +3,8 @@
   |
 6 |         type T;
   |              ^- help: indicate the anonymous lifetime: `<'_>`
+  |
+  = note: assuming a `'static` lifetime...
 
 error[E0106]: missing lifetime specifier
  --> $DIR/unsupported_elided.rs:8:24
@@ -14,4 +16,4 @@
 help: consider introducing a named lifetime parameter
   |
 8 |         fn f<'a>(t: &'a T) -> &'a str;
-  |             ^^^^    ^^^^^     ^^^
+  |             ++++     ++        ++
diff --git a/tests/ui/vec_opaque.stderr b/tests/ui/vec_opaque.stderr
index b8dad91..3f208fe 100644
--- a/tests/ui/vec_opaque.stderr
+++ b/tests/ui/vec_opaque.stderr
@@ -16,7 +16,8 @@
 22  |         type Job = crate::handle::Job;
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque`
     |
-   ::: $WORKSPACE/src/extern_type.rs
+note: required by a bound in `verify_extern_kind`
+   --> $DIR/extern_type.rs:186:41
     |
-    | pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
-    |                                         ----------- required by this bound in `verify_extern_kind`
+186 | pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
+    |                                         ^^^^^^^^^^^ required by this bound in `verify_extern_kind`
diff --git a/tests/ui/vector_autotraits.rs b/tests/ui/vector_autotraits.rs
new file mode 100644
index 0000000..cc918d5
--- /dev/null
+++ b/tests/ui/vector_autotraits.rs
@@ -0,0 +1,21 @@
+use cxx::CxxVector;
+
+#[cxx::bridge]
+mod ffi {
+    extern "C++" {
+        type ThreadSafe;
+        type NotThreadSafe;
+    }
+
+    impl CxxVector<ThreadSafe> {}
+    impl CxxVector<NotThreadSafe> {}
+}
+
+unsafe impl Send for ffi::ThreadSafe {}
+
+fn assert_send<T: Send>() {}
+
+fn main() {
+    assert_send::<CxxVector<ffi::ThreadSafe>>();
+    assert_send::<CxxVector<ffi::NotThreadSafe>>();
+}
diff --git a/tests/ui/vector_autotraits.stderr b/tests/ui/vector_autotraits.stderr
new file mode 100644
index 0000000..52fd2a4
--- /dev/null
+++ b/tests/ui/vector_autotraits.stderr
@@ -0,0 +1,22 @@
+error[E0277]: `*const cxx::void` cannot be sent between threads safely
+  --> $DIR/vector_autotraits.rs:20:5
+   |
+20 |     assert_send::<CxxVector<ffi::NotThreadSafe>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const cxx::void` cannot be sent between threads safely
+   |
+   = help: within `CxxVector<NotThreadSafe>`, the trait `Send` is not implemented for `*const cxx::void`
+   = note: required because it appears within the type `[*const cxx::void; 0]`
+   = note: required because it appears within the type `cxx::private::Opaque`
+note: required because it appears within the type `NotThreadSafe`
+  --> $DIR/vector_autotraits.rs:7:14
+   |
+7  |         type NotThreadSafe;
+   |              ^^^^^^^^^^^^^
+   = note: required because it appears within the type `[NotThreadSafe]`
+   = note: required because it appears within the type `PhantomData<[NotThreadSafe]>`
+   = note: required because it appears within the type `CxxVector<NotThreadSafe>`
+note: required by a bound in `assert_send`
+  --> $DIR/vector_autotraits.rs:16:19
+   |
+16 | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
diff --git a/tests/ui/wrong_type_id.stderr b/tests/ui/wrong_type_id.stderr
index 2d8e50a..b66bb26 100644
--- a/tests/ui/wrong_type_id.stderr
+++ b/tests/ui/wrong_type_id.stderr
@@ -4,10 +4,10 @@
 11  |         type ByteRange = crate::here::StringPiece;
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 15 elements, found one with 17 elements
     |
-   ::: $WORKSPACE/src/extern_type.rs
-    |
-    | pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
-    |                                         ------- required by this bound in `verify_extern_type`
-    |
     = note: expected tuple `(f, o, l, l, y, (), B, y, t, e, R, a, n, g, e)`
                found tuple `(f, o, l, l, y, (), S, t, r, i, n, g, P, i, e, c, e)`
+note: required by a bound in `verify_extern_type`
+   --> $DIR/extern_type.rs:183:41
+    |
+183 | pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
+    |                                         ^^^^^^^ required by this bound in `verify_extern_type`
diff --git a/third-party/BUCK b/third-party/BUCK
index 84a5e18..2633da8 100644
--- a/third-party/BUCK
+++ b/third-party/BUCK
@@ -1,13 +1,15 @@
 # To be generated by Facebook's `reindeer` tool once that is open source.
 
+load("//tools/buck:rust_library.bzl", "rust_library")
+
 rust_library(
     name = "bitflags",
-    srcs = glob(["vendor/bitflags-1.2.1/src/**"]),
+    srcs = glob(["vendor/bitflags-1.3.2/src/**"]),
 )
 
 rust_library(
     name = "cc",
-    srcs = glob(["vendor/cc-1.0.67/src/**"]),
+    srcs = glob(["vendor/cc-1.0.69/src/**"]),
     visibility = ["PUBLIC"],
 )
 
@@ -41,25 +43,21 @@
 
 rust_library(
     name = "proc-macro2",
-    srcs = glob(["vendor/proc-macro2-1.0.26/src/**"]),
-    visibility = ["PUBLIC"],
+    srcs = glob(["vendor/proc-macro2-1.0.28/src/**"]),
+    build_script = "vendor/proc-macro2-1.0.28/build.rs",
     features = [
         "proc-macro",
         "span-locations",
     ],
-    rustc_flags = [
-        "--cfg=span_locations",
-        "--cfg=use_proc_macro",
-        "--cfg=wrap_proc_macro",
-    ],
+    visibility = ["PUBLIC"],
     deps = [":unicode-xid"],
 )
 
 rust_library(
     name = "quote",
     srcs = glob(["vendor/quote-1.0.9/src/**"]),
-    visibility = ["PUBLIC"],
     features = ["proc-macro"],
+    visibility = ["PUBLIC"],
     deps = [":proc-macro2"],
 )
 
@@ -72,8 +70,8 @@
 
 rust_library(
     name = "syn",
-    srcs = glob(["vendor/syn-1.0.68/src/**"]),
-    visibility = ["PUBLIC"],
+    srcs = glob(["vendor/syn-1.0.75/src/**"]),
+    build_script = "vendor/syn-1.0.75/build.rs",
     features = [
         "clone-impls",
         "derive",
@@ -82,6 +80,7 @@
         "printing",
         "proc-macro",
     ],
+    visibility = ["PUBLIC"],
     deps = [
         ":proc-macro2",
         ":quote",
@@ -107,5 +106,5 @@
 
 rust_library(
     name = "unicode-xid",
-    srcs = glob(["vendor/unicode-xid-0.2.1/src/**"]),
+    srcs = glob(["vendor/unicode-xid-0.2.2/src/**"]),
 )
diff --git a/third-party/BUILD b/third-party/BUILD
index cf1a288..1760b70 100644
--- a/third-party/BUILD
+++ b/third-party/BUILD
@@ -1,17 +1,18 @@
 load(
-    "//tools/bazel:rust.bzl",
+    "//tools/bazel:third_party.bzl",
+    cargo_build_script = "third_party_cargo_build_script",
     glob = "third_party_glob",
     rust_library = "third_party_rust_library",
 )
 
 rust_library(
     name = "bitflags",
-    srcs = glob(["vendor/bitflags-1.2.1/src/**"]),
+    srcs = glob(["vendor/bitflags-1.3.2/src/**"]),
 )
 
 rust_library(
     name = "cc",
-    srcs = glob(["vendor/cc-1.0.67/src/**"]),
+    srcs = glob(["vendor/cc-1.0.69/src/**"]),
     visibility = ["//visibility:public"],
 )
 
@@ -45,18 +46,26 @@
 
 rust_library(
     name = "proc-macro2",
-    srcs = glob(["vendor/proc-macro2-1.0.26/src/**"]),
+    srcs = glob(["vendor/proc-macro2-1.0.28/src/**"]),
     crate_features = [
         "proc-macro",
         "span-locations",
     ],
-    rustc_flags = [
-        "--cfg=span_locations",
-        "--cfg=use_proc_macro",
-        "--cfg=wrap_proc_macro",
-    ],
     visibility = ["//visibility:public"],
-    deps = [":unicode-xid"],
+    deps = [
+        ":proc-macro2@build",
+        ":unicode-xid",
+    ],
+)
+
+cargo_build_script(
+    name = "proc-macro2@build",
+    srcs = ["vendor/proc-macro2-1.0.28/build.rs"],
+    crate_features = [
+        "proc-macro",
+        "span-locations",
+    ],
+    crate_name = "build",
 )
 
 rust_library(
@@ -76,7 +85,7 @@
 
 rust_library(
     name = "syn",
-    srcs = glob(["vendor/syn-1.0.68/src/**"]),
+    srcs = glob(["vendor/syn-1.0.75/src/**"]),
     crate_features = [
         "clone-impls",
         "derive",
@@ -89,10 +98,25 @@
     deps = [
         ":proc-macro2",
         ":quote",
+        ":syn@build",
         ":unicode-xid",
     ],
 )
 
+cargo_build_script(
+    name = "syn@build",
+    srcs = ["vendor/syn-1.0.75/build.rs"],
+    crate_features = [
+        "clone-impls",
+        "derive",
+        "full",
+        "parsing",
+        "printing",
+        "proc-macro",
+    ],
+    crate_name = "build",
+)
+
 rust_library(
     name = "termcolor",
     srcs = glob(["vendor/termcolor-1.1.2/src/**"]),
@@ -111,5 +135,5 @@
 
 rust_library(
     name = "unicode-xid",
-    srcs = glob(["vendor/unicode-xid-0.2.1/src/**"]),
+    srcs = glob(["vendor/unicode-xid-0.2.2/src/**"]),
 )
diff --git a/third-party/Cargo.lock b/third-party/Cargo.lock
index a95e737..0a3d543 100644
--- a/third-party/Cargo.lock
+++ b/third-party/Cargo.lock
@@ -3,6 +3,12 @@
 version = 3
 
 [[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
 name = "ansi_term"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -23,21 +29,42 @@
 ]
 
 [[package]]
-name = "bitflags"
-version = "1.2.1"
+name = "autocfg"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "cc"
-version = "1.0.67"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
 dependencies = [
  "jobserver",
 ]
 
 [[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-ast"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eed6681036a96f9855a75b08a9f14199e212017508a967d1d1e868f575f7d8e9"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "clap"
 version = "2.33.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -63,8 +90,17 @@
 ]
 
 [[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
 name = "cxx"
-version = "1.0.42"
+version = "1.0.54"
 dependencies = [
  "cc",
  "cxx-build",
@@ -79,7 +115,7 @@
 
 [[package]]
 name = "cxx-build"
-version = "1.0.42"
+version = "1.0.54"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -94,7 +130,7 @@
 
 [[package]]
 name = "cxx-gen"
-version = "0.7.42"
+version = "0.7.54"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -114,7 +150,7 @@
 
 [[package]]
 name = "cxxbridge-cmd"
-version = "1.0.42"
+version = "1.0.54"
 dependencies = [
  "clap",
  "codespan-reporting",
@@ -125,15 +161,20 @@
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.42"
+version = "1.0.54"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.42"
+version = "1.0.54"
 dependencies = [
+ "clang-ast",
  "cxx",
+ "flate2",
+ "memmap",
  "proc-macro2",
  "quote",
+ "serde",
+ "serde_json",
  "syn",
 ]
 
@@ -152,6 +193,18 @@
 checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
 
 [[package]]
+name = "flate2"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
 name = "glob"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -159,24 +212,24 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "itoa"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
 
 [[package]]
 name = "jobserver"
-version = "0.1.21"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
+checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
 dependencies = [
  "libc",
 ]
@@ -189,9 +242,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.92"
+version = "0.2.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
+checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
 
 [[package]]
 name = "link-cplusplus"
@@ -203,6 +256,26 @@
 ]
 
 [[package]]
+name = "memmap"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
+[[package]]
 name = "pkg-config"
 version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -210,9 +283,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.26"
+version = "1.0.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
 dependencies = [
  "unicode-xid",
 ]
@@ -228,9 +301,9 @@
 
 [[package]]
 name = "rustversion"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
+checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
 
 [[package]]
 name = "ryu"
@@ -246,18 +319,18 @@
 
 [[package]]
 name = "serde"
-version = "1.0.125"
+version = "1.0.129"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
+checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.125"
+version = "1.0.129"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
+checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -266,9 +339,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.64"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
 dependencies = [
  "itoa",
  "ryu",
@@ -283,9 +356,9 @@
 
 [[package]]
 name = "syn"
-version = "1.0.68"
+version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
+checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -321,9 +394,9 @@
 
 [[package]]
 name = "trybuild"
-version = "1.0.41"
+version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99471a206425fba51842a9186315f32d91c56eadc21ea4c21f847b59cf778f8b"
+checksum = "5bdaf2a1d317f3d58b44b31c7f6436b9b9acafe7bddfeace50897c2b804d7792"
 dependencies = [
  "dissimilar",
  "glob",
@@ -342,9 +415,9 @@
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
 [[package]]
 name = "vec_map"
diff --git a/tools/bazel/rust.bzl b/tools/bazel/rust.bzl
deleted file mode 100644
index 9f71923..0000000
--- a/tools/bazel/rust.bzl
+++ /dev/null
@@ -1,29 +0,0 @@
-"""A module wrapping the core rules of `rules_rust`"""
-
-load(
-    "@rules_rust//rust:rust.bzl",
-    _rust_binary = "rust_binary",
-    _rust_library = "rust_library",
-    _rust_test = "rust_test",
-)
-load("@third-party//:vendor.bzl", "vendored")
-
-def third_party_glob(include):
-    return vendored and native.glob(include)
-
-def rust_binary(edition = "2018", **kwargs):
-    _rust_binary(edition = edition, **kwargs)
-
-def third_party_rust_binary(rustc_flags = [], **kwargs):
-    rustc_flags = rustc_flags + ["--cap-lints=allow"]
-    rust_binary(rustc_flags = rustc_flags, **kwargs)
-
-def rust_library(edition = "2018", **kwargs):
-    _rust_library(edition = edition, **kwargs)
-
-def third_party_rust_library(rustc_flags = [], **kwargs):
-    rustc_flags = rustc_flags + ["--cap-lints=allow"]
-    rust_library(rustc_flags = rustc_flags, **kwargs)
-
-def rust_test(edition = "2018", **kwargs):
-    _rust_test(edition = edition, **kwargs)
diff --git a/tools/bazel/third_party.bzl b/tools/bazel/third_party.bzl
new file mode 100644
index 0000000..7f51c46
--- /dev/null
+++ b/tools/bazel/third_party.bzl
@@ -0,0 +1,18 @@
+load("@rules_rust//cargo:cargo_build_script.bzl", "cargo_build_script")
+load("@rules_rust//rust:rust.bzl", "rust_binary", "rust_library")
+load("@third-party//:vendor.bzl", "vendored")
+
+def third_party_glob(include):
+    return vendored and native.glob(include)
+
+def third_party_cargo_build_script(rustc_flags = [], **kwargs):
+    rustc_flags = rustc_flags + ["--cap-lints=allow"]
+    cargo_build_script(rustc_flags = rustc_flags, **kwargs)
+
+def third_party_rust_binary(rustc_flags = [], **kwargs):
+    rustc_flags = rustc_flags + ["--cap-lints=allow"]
+    rust_binary(rustc_flags = rustc_flags, **kwargs)
+
+def third_party_rust_library(rustc_flags = [], **kwargs):
+    rustc_flags = rustc_flags + ["--cap-lints=allow"]
+    rust_library(rustc_flags = rustc_flags, **kwargs)
diff --git a/tools/bazel/vendor.bzl b/tools/bazel/vendor.bzl
index e404ad9..e51adb7 100644
--- a/tools/bazel/vendor.bzl
+++ b/tools/bazel/vendor.bzl
@@ -2,6 +2,8 @@
 of a crate in the current workspace.
 """
 
+load("@rules_rust//rust:repositories.bzl", "DEFAULT_RUST_VERSION", "load_arbitrary_tool")
+
 def _impl(repository_ctx):
     # Link cxx repository into @third-party.
     lockfile = repository_ctx.path(repository_ctx.attr.lockfile)
@@ -14,8 +16,27 @@
     root_lockfile = repository_ctx.path("workspace/Cargo.lock")
     _copy_file(repository_ctx, src = vendor_lockfile, dst = root_lockfile)
 
-    # Execute cargo vendor.
-    cmd = ["cargo", "vendor", "--versioned-dirs", "third-party/vendor"]
+    # Figure out which version of cargo to use.
+    if repository_ctx.attr.target_triple:
+        target_triple = repository_ctx.attr.target_triple
+    elif "mac" in repository_ctx.os.name:
+        target_triple = "x86_64-apple-darwin"
+    elif "windows" in repository_ctx.os.name:
+        target_triple = "x86_64-pc-windows-msvc"
+    else:
+        target_triple = "x86_64-unknown-linux-gnu"
+
+    # Download cargo.
+    load_arbitrary_tool(
+        ctx = repository_ctx,
+        tool_name = "cargo",
+        tool_subdirectories = ["cargo"],
+        version = repository_ctx.attr.cargo_version,
+        iso_date = repository_ctx.attr.cargo_iso_date,
+        target_triple = target_triple,
+    )
+
+    cmd = ["{}/bin/cargo".format(repository_ctx.path(".")), "vendor", "--versioned-dirs", "third-party/vendor"]
     result = repository_ctx.execute(
         cmd,
         quiet = True,
@@ -54,6 +75,16 @@
 vendor = repository_rule(
     doc = "A rule used to vendor the dependencies of a crate in the current workspace",
     attrs = {
+        "cargo_version": attr.string(
+            doc = "The version of cargo to use",
+            default = DEFAULT_RUST_VERSION,
+        ),
+        "cargo_iso_date": attr.string(
+            doc = "The date of the tool (or None, if the version is a specific version)",
+        ),
+        "target_triple": attr.string(
+            doc = "The target triple of the cargo binary to download",
+        ),
         "lockfile": attr.label(
             doc = "A lockfile providing the set of crates to vendor",
         ),
diff --git a/tools/buck/rust_library.bzl b/tools/buck/rust_library.bzl
new file mode 100644
index 0000000..67ec2ac
--- /dev/null
+++ b/tools/buck/rust_library.bzl
@@ -0,0 +1,34 @@
+load("//tools/buck:genrule.bzl", "genrule")
+
+def rust_library(
+        name,
+        srcs,
+        features = [],
+        rustc_flags = [],
+        build_script = None,
+        **kwargs):
+    if build_script:
+        rust_binary(
+            name = "%s@build" % name,
+            srcs = srcs + [build_script],
+            crate = "build",
+            crate_root = build_script,
+            features = features,
+            rustc_flags = rustc_flags,
+        )
+
+        genrule(
+            name = "%s@cfg" % name,
+            out = "output",
+            cmd = "env RUSTC=rustc TARGET= $(exe :%s@build) | sed -n s/^cargo:rustc-cfg=/--cfg=/p > ${OUT}" % name,
+        )
+
+        rustc_flags = rustc_flags + ["@$(location :%s@cfg)" % name]
+
+    native.rust_library(
+        name = name,
+        srcs = srcs,
+        features = features,
+        rustc_flags = rustc_flags,
+        **kwargs
+    )