aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:03:19 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:03:19 +0000
commit8ba26ef8bb01fa9a548050cea3717a88fcf70145 (patch)
tree7074b4eac93437c9400ada0c51f46843f16c60f7
parent44796ba17fff8dca24585e68db7b9cd47789f07c (diff)
parentf427b2a756cc7e3acbf5123e3fcdd7cd93b2465f (diff)
downloadcxx-android13-mainline-resolv-release.tar.gz
Change-Id: I2a63578c68d4dc4de9eac07ee1e0a81663554a13
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--Android.bp12
-rw-r--r--BUCK6
-rw-r--r--BUILD2
-rw-r--r--Cargo.toml8
-rw-r--r--METADATA12
-rw-r--r--WORKSPACE16
-rw-r--r--book/src/binding/str.md1
-rw-r--r--book/src/binding/string.md8
-rw-r--r--book/src/build/bazel.md2
-rw-r--r--book/src/build/cmake.md7
-rw-r--r--build.rs6
-rw-r--r--demo/BUILD2
-rw-r--r--flags/Cargo.toml2
-rw-r--r--gen/build/Cargo.toml4
-rw-r--r--gen/build/src/lib.rs1
-rw-r--r--gen/cmd/Cargo.toml4
-rw-r--r--gen/cmd/src/main.rs1
-rw-r--r--gen/lib/Cargo.toml4
-rw-r--r--gen/lib/src/lib.rs1
-rw-r--r--gen/src/builtin.rs9
-rw-r--r--gen/src/check.rs2
-rw-r--r--gen/src/error.rs5
-rw-r--r--gen/src/mod.rs3
-rw-r--r--gen/src/write.rs113
-rw-r--r--include/cxx.h19
-rw-r--r--macro/Cargo.toml14
-rw-r--r--macro/src/clang.rs51
-rw-r--r--macro/src/derive.rs1
-rw-r--r--macro/src/expand.rs469
-rw-r--r--macro/src/lib.rs7
-rw-r--r--macro/src/load.rs315
-rw-r--r--src/cxx.cc87
-rw-r--r--src/cxx_string.rs56
-rw-r--r--src/cxx_vector.rs150
-rw-r--r--src/exception.rs3
-rw-r--r--src/extern_type.rs1
-rw-r--r--src/function.rs8
-rw-r--r--src/lib.rs9
-rw-r--r--src/memory.rs1
-rw-r--r--src/opaque.rs5
-rw-r--r--src/result.rs30
-rw-r--r--src/rust_slice.rs61
-rw-r--r--src/rust_str.rs17
-rw-r--r--src/rust_string.rs27
-rw-r--r--src/rust_type.rs2
-rw-r--r--src/rust_vec.rs50
-rw-r--r--src/shared_ptr.rs12
-rw-r--r--src/symbols/exception.rs2
-rw-r--r--src/symbols/rust_slice.rs16
-rw-r--r--src/symbols/rust_str.rs12
-rw-r--r--src/symbols/rust_string.rs54
-rw-r--r--src/symbols/rust_vec.rs21
-rw-r--r--src/unique_ptr.rs69
-rw-r--r--src/unwind.rs2
-rw-r--r--src/weak_ptr.rs19
-rw-r--r--syntax/attrs.rs25
-rw-r--r--syntax/check.rs62
-rw-r--r--syntax/discriminant.rs26
-rw-r--r--syntax/doc.rs4
-rw-r--r--syntax/error.rs7
-rw-r--r--syntax/file.rs37
-rw-r--r--syntax/impls.rs6
-rw-r--r--syntax/mod.rs16
-rw-r--r--syntax/names.rs9
-rw-r--r--syntax/parse.rs37
-rw-r--r--syntax/tokens.rs16
-rw-r--r--syntax/trivial.rs57
-rw-r--r--syntax/types.rs22
-rw-r--r--tests/BUILD2
-rw-r--r--tests/ffi/lib.rs5
-rw-r--r--tests/ffi/tests.cc28
-rw-r--r--tests/ffi/tests.h2
-rw-r--r--tests/test.rs34
-rw-r--r--tests/ui/array_len_suffix.stderr2
-rw-r--r--tests/ui/derive_nonclone.rs13
-rw-r--r--tests/ui/derive_nonclone.stderr7
-rw-r--r--tests/ui/expected_named.stderr2
-rw-r--r--tests/ui/opaque_autotraits.stderr59
-rw-r--r--tests/ui/opaque_not_sized.stderr16
-rw-r--r--tests/ui/reserved_lifetime.rs10
-rw-r--r--tests/ui/reserved_lifetime.stderr5
-rw-r--r--tests/ui/rust_pinned.stderr25
-rw-r--r--tests/ui/slice_of_type_alias.rs30
-rw-r--r--tests/ui/slice_of_type_alias.stderr11
-rw-r--r--tests/ui/slice_unsupported.stderr6
-rw-r--r--tests/ui/unique_ptr_to_opaque.stderr8
-rw-r--r--tests/ui/unsupported_elided.stderr4
-rw-r--r--tests/ui/vec_opaque.stderr7
-rw-r--r--tests/ui/vector_autotraits.rs21
-rw-r--r--tests/ui/vector_autotraits.stderr22
-rw-r--r--tests/ui/wrong_type_id.stderr10
-rw-r--r--third-party/BUCK25
-rw-r--r--third-party/BUILD48
-rw-r--r--third-party/Cargo.lock141
-rw-r--r--tools/bazel/rust.bzl29
-rw-r--r--tools/bazel/third_party.bzl18
-rw-r--r--tools/bazel/vendor.bzl35
-rw-r--r--tools/buck/rust_library.bzl34
99 files changed, 2167 insertions, 639 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3fafd9ba..0b82cd99 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,6 +54,7 @@ jobs:
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 @@ jobs:
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 014c9372..05ef3874 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,13 @@ rust_library {
],
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 @@ cc_library_static {
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 da6fcb24..86174e97 100644
--- a/BUCK
+++ b/BUCK
@@ -25,19 +25,19 @@ rust_binary(
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 24a1c8b6..c2c2edfd 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 e2b189ec..0414c727 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 @@ default = ["cxxbridge-flags/default"] # c++11
"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 2b3490cf..85611d61 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 @@ third_party {
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 17a0af54..08aacf21 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 a4820aaf..9c1e0a77 100644
--- a/book/src/binding/str.md
+++ b/book/src/binding/str.md
@@ -30,6 +30,7 @@ public:
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 a7d0790b..d564e00c 100644
--- a/book/src/binding/string.md
+++ b/book/src/binding/string.md
@@ -23,6 +23,10 @@ public:
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 @@ public:
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 08edb19f..8f910550 100644
--- a/book/src/build/bazel.md
+++ b/book/src/build/bazel.md
@@ -70,7 +70,7 @@ def rust_cxx_bridge(name, src, deps = []):
# 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 ed3cb61d..4b50746c 100644
--- a/book/src/build/cmake.md
+++ b/book/src/build/cmake.md
@@ -22,3 +22,10 @@ what is available in these links, feel free to make a PR adding it to this list.
- 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 f7994418..a953639a 100644
--- a/build.rs
+++ b/build.rs
@@ -28,6 +28,12 @@ fn main() {
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 cce8119c..4ab5ecb7 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 87c796cb..baf1157a 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 33f17dff..393fc1ce 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 @@ lazy_static = "1.4"
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 63b2cf63..b8a463c3 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 7db02062..4b3a299f 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 @@ clap = "2.33"
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 f419dad4..1c15db63 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 ff33d979..37d81687 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 @@ cc = "1.0.49"
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 e3eca5e7..411953b2 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 eaaa08d1..7ac9209c 100644
--- a/gen/src/builtin.rs
+++ b/gen/src/builtin.rs
@@ -30,6 +30,7 @@ pub struct Builtins<'a> {
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 @@ pub(super) fn write(out: &mut OutFile) {
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 35929ad3..15add20a 100644
--- a/gen/src/check.rs
+++ b/gen/src/check.rs
@@ -4,7 +4,7 @@ use crate::syntax::{error, Api};
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 2c8287f3..3672e26e 100644
--- a/gen/src/error.rs
+++ b/gen/src/error.rs
@@ -87,12 +87,11 @@ pub(crate) fn report(error: impl StdError) -> impl Display {
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 3d12c71d..d8b90d0d 100644
--- a/gen/src/mod.rs
+++ b/gen/src/mod.rs
@@ -130,7 +130,8 @@ pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
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 9f9c0391..a3b9c9fa 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -9,8 +9,8 @@ use crate::syntax::set::UnorderedSet;
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 @@ fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
}
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 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
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_struct_decl(out: &mut OutFile, ident: &Pair) {
}
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 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
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_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
}
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 @@ fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
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 write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
}
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 @@ fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
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 @@ fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pa
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_decl_impl(
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 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
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 @@ fn write_rust_function_shim_impl(
out: &mut OutFile,
local_name: &str,
sig: &Signature,
+ doc: &Doc,
invoke: &Symbol,
indirect_call: bool,
) {
@@ -954,6 +986,12 @@ fn write_rust_function_shim_impl(
// 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 @@ fn write_rust_vec_extern(out: &mut OutFile, key: NamedImplKey) {
);
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 @@ fn write_rust_vec_impl(out: &mut OutFile, key: NamedImplKey) {
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 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) {
// 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 @@ fn write_shared_ptr(out: &mut OutFile, key: NamedImplKey) {
// 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 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
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 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
);
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 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
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 cdc63fbf..dffcb01a 100644
--- a/include/cxx.h
+++ b/include/cxx.h
@@ -43,6 +43,8 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ void panic [[noreturn]] (const char *msg);
#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 @@ bool Slice<T>::empty() const noexcept {
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 @@ Slice<T>::iterator::operator->() const noexcept {
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 a3df1018..65f15c3a 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 @@ categories = ["development-tools::ffi"]
[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 00000000..099d5a68
--- /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 2f770951..ea36e3e3 100644
--- a/macro/src/derive.rs
+++ b/macro/src/derive.rs
@@ -151,6 +151,7 @@ fn struct_default(strct: &Struct, span: Span) -> TokenStream {
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 7c194ad2..5a879cbd 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -14,7 +14,7 @@ use crate::{derive, generics};
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 @@ pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
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 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
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 @@ fn expand_enum(enm: &Enum) -> TokenStream {
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 @@ fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
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 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
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 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
.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 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
.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 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
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::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_spanned!(span=> ::std::boxed::Box::from_raw(#call))
+ }
+ }
Type::RustVec(vec) => {
if vec.inner == RustString {
- quote!(#call.into_vec_string())
+ 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!(#call.into_vec())
+ quote_spanned!(span=> ::cxx::UniquePtr::from_raw(#call))
}
}
- Type::UniquePtr(_) => quote!(::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 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
};
&elided_generics
};
- quote! {
+ quote_spanned! {ident.span()=>
impl #generics #receiver_ident #receiver_generics {
#doc
#attrs
@@ -718,6 +756,7 @@ fn expand_function_pointer_trampoline(
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 @@ fn expand_function_pointer_trampoline(
local_name,
catch_unwind_label,
None,
+ Some(&efn.generics),
+ body_span,
);
let var = &var.rust;
@@ -736,9 +777,9 @@ fn expand_function_pointer_trampoline(
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 @@ fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
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 @@ fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
local_name,
catch_unwind_label,
invoke,
+ None,
+ body_span,
)
}
@@ -874,138 +918,166 @@ fn expand_rust_function_shim_impl(
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 @@ fn expand_rust_function_shim_impl(
};
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 @@ fn expand_rust_function_shim_super(
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 @@ fn expand_rust_vec(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl
}
#[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 @@ fn expand_unique_ptr(
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 @@ fn expand_unique_ptr(
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 @@ fn expand_shared_ptr(
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 @@ fn expand_cxx_vector(
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 @@ fn expand_cxx_vector(
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 @@ fn expand_cxx_vector(
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 indirect_return(sig: &Signature, types: &Types) -> bool {
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) => {
+ let star = Token![*](ampersand.span);
+ match ty.mutable {
+ false => quote!(#star const ::std::ffi::c_void),
+ true => quote!(#star #mutability ::std::ffi::c_void),
+ }
}
- 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),
- },
_ => 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 f8e79034..324881d8 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 generics;
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 00000000..d769ebf6
--- /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 c0ef7389..5dca531b 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -22,6 +22,13 @@ std::size_t cxxbridge1$cxx_string$length(const std::string &s) noexcept {
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$cxx_string$push(std::string &s, const std::uint8_t *ptr,
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(String &&other) noexcept : repr(other.repr) {
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 @@ String::String(const char *s, std::size_t len) {
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 @@ std::size_t String::length() const noexcept {
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::size() const noexcept { return cxxbridge1$str$len(this); }
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 @@ using isize_if_unique =
} // 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 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
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 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
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 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
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 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
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 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
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 dce7053d..626c2c85 100644
--- a/src/cxx_string.rs
+++ b/src/cxx_string.rs
@@ -19,6 +19,10 @@ extern "C" {
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 @@ impl CxxString {
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 @@ pub struct StackString {
space: MaybeUninit<[usize; 8]>,
}
+#[allow(missing_docs)]
impl StackString {
pub fn new() -> Self {
StackString {
@@ -222,9 +270,11 @@ impl StackString {
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 16433417..d1fa23a2 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -8,9 +8,8 @@ use core::ffi::c_void;
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 @@ use core::slice;
/// 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 @@ where
/// [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 @@ where
///
/// [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 @@ where
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 @@ pub unsafe trait VectorElement: Sized {
#[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)]
+ fn __unique_ptr_null() -> MaybeUninit<*mut c_void>;
#[doc(hidden)]
- unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
+ unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void>;
#[doc(hidden)]
- unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
+ unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self>;
#[doc(hidden)]
- unsafe fn __unique_ptr_drop(repr: *mut c_void);
+ 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 @@ macro_rules! impl_vector_element {
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 {
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!(isize);
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 f61e8fa9..2ae470e7 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 Display for Exception {
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 35057acb..8c9c2860 100644
--- a/src/extern_type.rs
+++ b/src/extern_type.rs
@@ -167,6 +167,7 @@ pub mod kind {
/// 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 1166b3d4..f0a20100 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 19a708c5..9880e711 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 @@ chars! {
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 441d3d89..fd8df12a 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 3c8f5362..e0f8ce2c 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 @@ use core::mem;
// . !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 f41639a1..d7a31f02 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 @@ where
{
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 @@ unsafe fn to_c_error(msg: String) -> Result {
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 b4b5f2cb..06963117 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 9bc26145..b1b46e3e 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 a5fa3f49..051e35c3 100644
--- a/src/rust_string.rs
+++ b/src/rust_string.rs
@@ -1,14 +1,18 @@
+#![allow(missing_docs)]
+
use alloc::string::String;
-use core::mem;
+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 @@ impl RustString {
}
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) }
+ }
+}
+
+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::<String>());
-const_assert_eq!(mem::align_of::<usize>(), mem::align_of::<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 7bcf440d..eacb5309 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 126fdbf9..9f4484db 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 @@ impl<T> RustVec<T> {
}
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 @@ impl RustVec<RustString> {
}
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 @@ impl RustVec<RustString> {
}
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 66b988ba..317773d4 100644
--- a/src/shared_ptr.rs
+++ b/src/shared_ptr.rs
@@ -15,7 +15,7 @@ pub struct SharedPtr<T>
where
T: SharedPtrTarget,
{
- repr: [*mut c_void; 2],
+ repr: [MaybeUninit<*mut c_void>; 2],
ty: PhantomData<T>,
}
@@ -216,7 +216,7 @@ macro_rules! impl_shared_ptr_target {
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 @@ macro_rules! impl_shared_ptr_target {
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 @@ macro_rules! impl_shared_ptr_target {
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 @@ macro_rules! impl_shared_ptr_target {
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 @@ macro_rules! impl_shared_ptr_target {
fn __drop(this: *mut c_void);
}
}
- __drop(this);
+ unsafe { __drop(this) }
}
}
};
diff --git a/src/symbols/exception.rs b/src/symbols/exception.rs
index 0c1bb876..cf0701ba 100644
--- a/src/symbols/exception.rs
+++ b/src/symbols/exception.rs
@@ -4,7 +4,7 @@ use core::slice;
#[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 055b4dee..df215acf 100644
--- a/src/symbols/rust_slice.rs
+++ b/src/symbols/rust_slice.rs
@@ -3,20 +3,18 @@ use core::mem::MaybeUninit;
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 a9e84efb..3d5ec344 100644
--- a/src/symbols/rust_str.rs
+++ b/src/symbols/rust_str.rs
@@ -6,20 +6,24 @@ use core::str;
#[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 91fd78a3..49d40697 100644
--- a/src/symbols/rust_string.rs
+++ b/src/symbols/rust_string.rs
@@ -7,24 +7,47 @@ use core::str;
#[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 @@ unsafe extern "C" fn string_from(
#[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 @@ unsafe extern "C" fn string_len(this: &String) -> usize {
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 a26a1569..6f2dab9d 100644
--- a/src/symbols/rust_vec.rs
+++ b/src/symbols/rust_vec.rs
@@ -7,50 +7,51 @@ use std::os::raw::c_char;
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 836f4677..63a1ca78 100644
--- a/src/unique_ptr.rs
+++ b/src/unique_ptr.rs
@@ -6,10 +6,9 @@ use crate::ExternType;
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 @@ pub struct UniquePtr<T>
where
T: UniquePtrTarget,
{
- repr: *mut c_void,
+ repr: MaybeUninit<*mut c_void>,
ty: PhantomData<T>,
}
@@ -104,7 +103,7 @@ where
/// 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 @@ pub unsafe trait UniquePtrTarget {
#[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 @@ pub unsafe trait UniquePtrTarget {
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 @@ unsafe impl UniquePtrTarget for CxxString {
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 @@ where
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 36f6ae3d..4967a219 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 8291d59b..8a9f1a68 100644
--- a/src/weak_ptr.rs
+++ b/src/weak_ptr.rs
@@ -16,7 +16,7 @@ pub struct WeakPtr<T>
where
T: WeakPtrTarget,
{
- repr: [*mut c_void; 2],
+ repr: [MaybeUninit<*mut c_void>; 2],
ty: PhantomData<T>,
}
@@ -91,8 +91,11 @@ where
}
}
-// 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 @@ macro_rules! impl_weak_ptr_target {
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 @@ macro_rules! impl_weak_ptr_target {
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 @@ macro_rules! impl_weak_ptr_target {
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 @@ macro_rules! impl_weak_ptr_target {
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 @@ macro_rules! impl_weak_ptr_target {
fn __drop(this: *mut c_void);
}
}
- __drop(this);
+ unsafe { __drop(this) }
}
}
};
diff --git a/syntax/attrs.rs b/syntax/attrs.rs
index 4808f2e1..fa6c8097 100644
--- a/syntax/attrs.rs
+++ b/syntax/attrs.rs
@@ -4,7 +4,7 @@ use crate::syntax::Atom::{self, *};
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 struct Parser<'a> {
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 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
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 OtherAttrs {
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 bab2dec5..698782f9 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -2,24 +2,40 @@ use crate::syntax::atom::Atom::{self, *};
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_ptr(cx: &mut Check, ty: &Ptr) {
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_type_fn(cx: &mut Check, ty: &Signature) {
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_struct(cx: &mut Check, strct: &Struct) {
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_enum(cx: &mut Check, enm: &Enum) {
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 @@ fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
}
}
+ 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_fn(cx: &mut Check, efn: &ExternFn) {
}
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_type_alias(cx: &mut Check, alias: &TypeAlias) {
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_name(cx: &mut Check, ident: &Ident) {
}
}
+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 80f7c0be..fff8f758 100644
--- a/syntax/discriminant.rs
+++ b/syntax/discriminant.rs
@@ -150,7 +150,7 @@ fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discr
}
impl Discriminant {
- const fn zero() -> Self {
+ pub const fn zero() -> Self {
Discriminant {
sign: Sign::Positive,
magnitude: 0,
@@ -179,6 +179,28 @@ impl Discriminant {
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 @@ impl Display for Discriminant {
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 60bb4da1..cd764fac 100644
--- a/syntax/doc.rs
+++ b/syntax/doc.rs
@@ -17,6 +17,10 @@ impl Doc {
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 a6723293..f40c4a8e 100644
--- a/syntax/error.rs
+++ b/syntax/error.rs
@@ -21,6 +21,7 @@ pub static ERRORS: &[Error] = &[
DISCRIMINANT_OVERFLOW,
DOT_INCLUDE,
DOUBLE_UNDERSCORE,
+ RESERVED_LIFETIME,
RUST_TYPE_BY_VALUE,
UNSUPPORTED_TYPE,
USE_NOT_ALLOWED,
@@ -68,6 +69,12 @@ pub static DOUBLE_UNDERSCORE: Error = Error {
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 fd6dd98b..99466b8e 100644
--- a/syntax/file.rs
+++ b/syntax/file.rs
@@ -91,17 +91,32 @@ impl Parse for Item {
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 8b0743b6..06d68dc2 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -339,6 +339,7 @@ impl PartialEq for Signature {
attrs: _,
visibility: _,
name: _,
+ colon_token: _,
ty,
} = arg;
let Var {
@@ -346,6 +347,7 @@ impl PartialEq for Signature {
attrs: _,
visibility: _,
name: _,
+ colon_token: _,
ty: ty2,
} = arg2;
ty == ty2
@@ -374,6 +376,7 @@ impl Hash for Signature {
attrs: _,
visibility: _,
name: _,
+ colon_token: _,
ty,
} = arg;
ty.hash(state);
@@ -393,6 +396,7 @@ impl PartialEq for Receiver {
lifetime,
mutable,
var: _,
+ colon_token: _,
ty,
shorthand: _,
pin_tokens: _,
@@ -404,6 +408,7 @@ impl PartialEq for Receiver {
lifetime: lifetime2,
mutable: mutable2,
var: _,
+ colon_token: _,
ty: ty2,
shorthand: _,
pin_tokens: _,
@@ -421,6 +426,7 @@ impl Hash for Receiver {
lifetime,
mutable,
var: _,
+ colon_token: _,
ty,
shorthand: _,
pin_tokens: _,
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 3d562931..1d986345 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -30,17 +30,17 @@ pub mod types;
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 struct Enum {
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 struct Var {
pub attrs: OtherAttrs,
pub visibility: Token![pub],
pub name: Pair,
+ pub colon_token: Token![:],
pub ty: Type,
}
@@ -184,6 +191,7 @@ pub struct Receiver {
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 cb6ace53..7a125ae7 100644
--- a/syntax/names.rs
+++ b/syntax/names.rs
@@ -9,7 +9,6 @@ use syn::punctuated::Punctuated;
#[derive(Clone)]
pub struct ForeignName {
text: String,
- span: Span,
}
impl Pair {
@@ -56,7 +55,7 @@ impl ForeignName {
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 @@ impl Display for ForeignName {
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 d7920761..32d36eb3 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -4,9 +4,9 @@ use crate::syntax::file::{Item, ItemForeignMod};
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 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) ->
};
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 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
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 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
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 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
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 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
generics,
brace_token,
variants,
+ variants_from_header,
+ variants_from_header_attr,
repr,
- repr_type,
explicit_repr,
})
}
@@ -560,6 +571,7 @@ fn parse_extern_fn(
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 @@ fn parse_extern_fn(
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 @@ fn parse_extern_fn(
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 @@ fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
.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 @@ fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
attrs,
visibility,
name,
+ colon_token,
ty,
})
})
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index c1a06a21..33f20fa3 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 @@ impl ToTokens for Var {
attrs: _,
visibility: _,
name,
+ colon_token: _,
ty,
} = self;
name.rust.to_tokens(tokens);
@@ -279,6 +280,15 @@ impl ToTokens for Signature {
}
}
+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 @@ impl ToTokens for ReceiverType<'_> {
lifetime,
mutable: _,
var: _,
+ colon_token: _,
ty,
shorthand: _,
pin_tokens,
@@ -337,6 +348,7 @@ impl ToTokens for ReceiverTypeSelf<'_> {
lifetime,
mutable: _,
var: _,
+ colon_token: _,
ty,
shorthand: _,
pin_tokens,
diff --git a/syntax/trivial.rs b/syntax/trivial.rs
index fe95e2b7..067e2d75 100644
--- a/syntax/trivial.rs
+++ b/syntax/trivial.rs
@@ -11,6 +11,7 @@ pub enum TrivialReason<'a> {
FunctionReturn(&'a ExternFn),
BoxTarget,
VecElement,
+ SliceElement { mutable: bool },
UnpinnedMut(&'a ExternFn),
}
@@ -105,6 +106,14 @@ pub fn required_trivial_reasons<'a>(
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 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display
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 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display
}
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 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display
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 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display
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 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display
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 af7916d7..c54682bd 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -7,7 +7,7 @@ use crate::syntax::set::{OrderedSet, UnorderedSet};
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 @@ impl<'a> Types<'a> {
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 @@ impl<'a> Types<'a> {
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 @@ impl<'a> Types<'a> {
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 7886e4fa..d4af3aff 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 fcbe1530..25b4ccdc 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -157,6 +157,10 @@ pub mod ffi {
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 @@ pub mod ffi {
}
impl Box<Shared> {}
+ impl CxxVector<SharedString> {}
}
mod other {
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index ba12ed45..df7ded07 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -336,13 +336,13 @@ void c_take_unique_ptr_string(std::unique_ptr<std::string> s) {
}
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_string(
}
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 @@ void c_take_callback(rust::Fn<size_t(rust::String)> callback) {
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 @@ extern "C" const char *cxx_run_test() noexcept {
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 74acbf4f..b624d393 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -160,6 +160,8 @@ void c_take_ref_rust_vec_index(const rust::Vec<uint8_t> &v);
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 32b8e832..1f0b1660 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -150,15 +150,15 @@ fn test_c_take() {
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 @@ fn test_c_callback() {
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 b72fc022..143bcb04 100644
--- a/tests/ui/array_len_suffix.stderr
+++ b/tests/ui/array_len_suffix.stderr
@@ -7,4 +7,4 @@ error[E0308]: mismatched types
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 58110289..00000000
--- 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 04eae4fd..00000000
--- 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 46764014..dab3b5a3 100644
--- a/tests/ui/expected_named.stderr
+++ b/tests/ui/expected_named.stderr
@@ -8,4 +8,4 @@ error[E0106]: missing lifetime specifier
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 4f469eff..15a2b64c 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 9818e444..b50a2699 100644
--- a/tests/ui/opaque_not_sized.stderr
+++ b/tests/ui/opaque_not_sized.stderr
@@ -2,10 +2,16 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
--> $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 00000000..179a4db5
--- /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 00000000..723572d9
--- /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 f16f9d55..8857681c 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 00000000..a7bbc114
--- /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 00000000..aff06f8d
--- /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 787076fb..2cbd26da 100644
--- a/tests/ui/slice_unsupported.stderr
+++ b/tests/ui/slice_unsupported.stderr
@@ -3,3 +3,9 @@ error: unsupported &mut [T] element type: opaque C++ type is not supported yet
|
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 19d76a3b..28e45cf5 100644
--- a/tests/ui/unique_ptr_to_opaque.stderr
+++ b/tests/ui/unique_ptr_to_opaque.stderr
@@ -4,4 +4,10 @@ error[E0271]: type mismatch resolving `<outside::C as ExternType>::Kind == Trivi
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 932076d9..8e8a986b 100644
--- a/tests/ui/unsupported_elided.stderr
+++ b/tests/ui/unsupported_elided.stderr
@@ -3,6 +3,8 @@ error[E0726]: implicit elided lifetime not allowed here
|
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 @@ error[E0106]: missing lifetime specifier
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 b8dad916..3f208fec 100644
--- a/tests/ui/vec_opaque.stderr
+++ b/tests/ui/vec_opaque.stderr
@@ -16,7 +16,8 @@ error[E0271]: type mismatch resolving `<handle::Job as ExternType>::Kind == Triv
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 00000000..cc918d58
--- /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 00000000..52fd2a41
--- /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 2d8e50aa..b66bb266 100644
--- a/tests/ui/wrong_type_id.stderr
+++ b/tests/ui/wrong_type_id.stderr
@@ -4,10 +4,10 @@ error[E0271]: type mismatch resolving `<StringPiece as ExternType>::Id == (f, o,
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 84a5e18b..2633da87 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(
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(
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 @@ rust_library(
"printing",
"proc-macro",
],
+ visibility = ["PUBLIC"],
deps = [
":proc-macro2",
":quote",
@@ -107,5 +106,5 @@ rust_library(
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 cf1a2883..1760b707 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(
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(
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 @@ rust_library(
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(
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 a95e737b..0a3d543d 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 @@ dependencies = [
]
[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+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 @@ dependencies = [
]
[[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 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.42"
+version = "1.0.54"
dependencies = [
"cc",
"codespan-reporting",
@@ -94,7 +130,7 @@ dependencies = [
[[package]]
name = "cxx-gen"
-version = "0.7.42"
+version = "0.7.54"
dependencies = [
"cc",
"codespan-reporting",
@@ -114,7 +150,7 @@ dependencies = [
[[package]]
name = "cxxbridge-cmd"
-version = "1.0.42"
+version = "1.0.54"
dependencies = [
"clap",
"codespan-reporting",
@@ -125,15 +161,20 @@ dependencies = [
[[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 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
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 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[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 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[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 @@ dependencies = [
]
[[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 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[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 @@ dependencies = [
[[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 @@ checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69"
[[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 @@ dependencies = [
[[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 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[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 @@ dependencies = [
[[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 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[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 9f71923a..00000000
--- 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 00000000..7f51c466
--- /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 e404ad99..e51adb7b 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 @@ def _impl(repository_ctx):
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 @@ def _log_cargo_vendor(repository_ctx, result):
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 00000000..67ec2ac7
--- /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
+ )