aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-12-13 12:17:50 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-12-13 12:17:50 +0000
commit0d1afe354ad53279047c74851ff9a1c827cdde3d (patch)
tree122709fa980d9a937b7808412db3e2cac040a10e
parent7268f2d44dcb8994162a1827a11f4df15bbce7a0 (diff)
parent3cd9d0cc2714449b23e0e3f62a17f4a0eb3299a8 (diff)
downloadbindgen-0d1afe354ad53279047c74851ff9a1c827cdde3d.tar.gz
Merge "Upgrade bindgen to 0.69.1" into main am: 3cd9d0cc27
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/bindgen/+/2840575 Change-Id: I612a5c59642a731bee0821548d54bc10d4bd6cd6 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp8
-rw-r--r--Cargo.toml46
-rw-r--r--Cargo.toml.orig55
-rw-r--r--METADATA10
-rw-r--r--README.md89
-rw-r--r--callbacks.rs35
-rw-r--r--clang.rs117
-rw-r--r--codegen/error.rs32
-rw-r--r--codegen/helpers.rs317
-rw-r--r--codegen/mod.rs1475
-rw-r--r--codegen/serialize.rs158
-rw-r--r--codegen/struct_layout.rs8
-rw-r--r--deps.rs49
-rw-r--r--extra_assertions.rs25
-rw-r--r--features.rs395
-rw-r--r--ir/analysis/has_vtable.rs2
-rw-r--r--ir/analysis/mod.rs13
-rw-r--r--ir/analysis/template_params.rs2
-rw-r--r--ir/annotations.rs2
-rw-r--r--ir/comp.rs24
-rw-r--r--ir/context.rs65
-rw-r--r--ir/enum_ty.rs15
-rw-r--r--ir/function.rs207
-rw-r--r--ir/int.rs9
-rw-r--r--ir/item.rs46
-rw-r--r--ir/layout.rs24
-rw-r--r--ir/module.rs5
-rw-r--r--ir/objc.rs27
-rw-r--r--ir/template.rs19
-rw-r--r--ir/ty.rs44
-rw-r--r--lib.rs206
-rw-r--r--options/as_args.rs2
-rw-r--r--options/mod.rs152
-rw-r--r--patches/autocxx.patch2190
-rw-r--r--regex_set.rs14
36 files changed, 1801 insertions, 4088 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 820d6ff..793a871 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "7d243056d335fdc4537f7bca73c06d01aae24ddc"
+ "sha1": "4f9fa49ca907b831fdc3aecdfaec36b16d03c8d8"
},
"path_in_vcs": "bindgen"
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index af0cb35..5f11192 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,7 +42,7 @@ rust_library_host {
name: "libbindgen",
crate_name: "bindgen",
cargo_env_compat: true,
- cargo_pkg_version: "0.65.1",
+ cargo_pkg_version: "0.69.1",
srcs: [
"lib.rs",
":copy_bindgen_build_out",
@@ -50,10 +50,8 @@ rust_library_host {
edition: "2018",
features: [
"__cli",
- "annotate-snippets",
"experimental",
"runtime",
- "which",
"which-rustfmt",
],
rustlibs: [
@@ -64,9 +62,7 @@ rust_library_host {
"liblazy_static",
"liblazycell",
"libpeeking_take_while",
- "libprettyplease",
"libproc_macro2",
- "libitertools",
"libquote",
"libregex",
"librustc_hash",
@@ -75,6 +71,4 @@ rust_library_host {
"libwhich",
],
compile_multilib: "first",
- product_available: true,
- vendor_available: true,
}
diff --git a/Cargo.toml b/Cargo.toml
index facd25a..24132d6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2018"
rust-version = "1.60.0"
name = "bindgen"
-version = "0.65.1"
+version = "0.69.1"
authors = [
"Jyun-Yan You <jyyou.tw@gmail.com>",
"Emilio Cobos Álvarez <emilio@crisal.io>",
@@ -24,7 +24,7 @@ build = "build.rs"
description = "Automatically generates Rust FFI bindings to C and C++ libraries."
homepage = "https://rust-lang.github.io/rust-bindgen/"
documentation = "https://docs.rs/bindgen"
-readme = "../README.md"
+readme = "README.md"
keywords = [
"bindings",
"ffi",
@@ -37,6 +37,29 @@ categories = [
license = "BSD-3-Clause"
repository = "https://github.com/rust-lang/rust-bindgen"
+[package.metadata.docs.rs]
+features = ["experimental"]
+
+[package.metadata.release]
+pre-release-hook = [
+ "../node_modules/doctoc/doctoc.js",
+ "../CHANGELOG.md",
+]
+release = true
+
+[[package.metadata.release.pre-release-replacements]]
+file = "../CHANGELOG.md"
+replace = """
+# Unreleased
+## Added
+## Changed
+## Removed
+## Fixed
+## Security
+
+# {{version}} ({{date}})"""
+search = "# Unreleased"
+
[lib]
name = "bindgen"
path = "lib.rs"
@@ -47,7 +70,7 @@ features = ["color"]
optional = true
[dependencies.bitflags]
-version = "1.0.3"
+version = "2.2.1"
[dependencies.cexpr]
version = "0.6"
@@ -70,7 +93,9 @@ optional = true
version = "0.1.2"
[dependencies.prettyplease]
-version = "0.2.0"
+version = "0.2.7"
+features = ["verbatim"]
+optional = true
[dependencies.proc-macro2]
version = "1"
@@ -109,16 +134,17 @@ default-features = false
[features]
__cli = []
+__testing_only_extra_assertions = []
+__testing_only_libclang_5 = []
+__testing_only_libclang_9 = []
default = [
"logging",
+ "prettyplease",
"runtime",
"which-rustfmt",
]
-experimental = ["annotate-snippets"]
-logging = ["log"]
+experimental = ["dep:annotate-snippets"]
+logging = ["dep:log"]
runtime = ["clang-sys/runtime"]
static = ["clang-sys/static"]
-testing_only_extra_assertions = []
-testing_only_libclang_5 = []
-testing_only_libclang_9 = []
-which-rustfmt = ["which"]
+which-rustfmt = ["dep:which"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 838524f..18f43c0 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -14,7 +14,7 @@ readme = "../README.md"
repository = "https://github.com/rust-lang/rust-bindgen"
documentation = "https://docs.rs/bindgen"
homepage = "https://rust-lang.github.io/rust-bindgen/"
-version = "0.65.1"
+version = "0.69.1"
edition = "2018"
build = "build.rs"
# If you change this, also update README.md and msrv in .github/workflows/bindgen.yml
@@ -25,35 +25,50 @@ name = "bindgen"
path = "lib.rs"
[dependencies]
-bitflags = "1.0.3"
+annotate-snippets = { version = "0.9.1", features = ["color"], optional = true }
+bitflags = "2.2.1"
cexpr = "0.6"
clang-sys = { version = "1", features = ["clang_6_0"] }
-lazycell = "1"
lazy_static = "1"
+lazycell = "1"
+log = { version = "0.4", optional = true }
peeking_take_while = "0.1.2"
+prettyplease = { version = "0.2.7", optional = true, features = ["verbatim"] }
+proc-macro2 = { version = "1", default-features = false }
quote = { version = "1", default-features = false }
-syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"]}
-regex = { version = "1.5", default-features = false , features = ["std", "unicode"] }
-which = { version = "4.2.1", optional = true, default-features = false }
-prettyplease = { version = "0.2.0" }
-annotate-snippets = { version = "0.9.1", features = ["color"], optional = true }
-shlex = "1"
+regex = { version = "1.5", default-features = false, features = ["std", "unicode"] }
rustc-hash = "1.0.1"
-proc-macro2 = { version = "1", default-features = false }
-log = { version = "0.4", optional = true }
+shlex = "1"
+syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] }
+which = { version = "4.2.1", optional = true, default-features = false }
[features]
-default = ["logging", "runtime", "which-rustfmt"]
-logging = ["log"]
+default = ["logging", "prettyplease", "runtime", "which-rustfmt"]
+logging = ["dep:log"]
static = ["clang-sys/static"]
runtime = ["clang-sys/runtime"]
# Dynamically discover a `rustfmt` binary using the `which` crate
-which-rustfmt = ["which"]
+which-rustfmt = ["dep:which"]
+experimental = ["dep:annotate-snippets"]
+
+## The following features are for internal use and they shouldn't be used if
+## you're not hacking on bindgen
+# Features used by `bindgen-cli`
__cli = []
-experimental = ["annotate-snippets"]
+# Features used for CI testing
+__testing_only_extra_assertions = []
+__testing_only_libclang_9 = []
+__testing_only_libclang_5 = []
+
+[package.metadata.docs.rs]
+features = ["experimental"]
+
+[package.metadata.release]
+release = true
+pre-release-hook = ["../node_modules/doctoc/doctoc.js", "../CHANGELOG.md"]
-# These features only exist for CI testing -- don't use them if you're not hacking
-# on bindgen!
-testing_only_extra_assertions = []
-testing_only_libclang_9 = []
-testing_only_libclang_5 = []
+# Add version and date to changelog file
+[[package.metadata.release.pre-release-replacements]]
+file = "../CHANGELOG.md"
+search = "# Unreleased"
+replace = "# Unreleased\n## Added\n## Changed\n## Removed\n## Fixed\n## Security\n\n# {{version}} ({{date}})"
diff --git a/METADATA b/METADATA
index 3a8c1e8..cca20de 100644
--- a/METADATA
+++ b/METADATA
@@ -1,6 +1,6 @@
# This project was upgraded with external_updater.
# Usage: tools/external_updater/updater.sh update rust/crates/bindgen
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
name: "bindgen"
description: "Automatically generates Rust FFI bindings to C and C++ libraries."
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/bindgen/bindgen-0.65.1.crate"
+ value: "https://static.crates.io/crates/bindgen/bindgen-0.69.1.crate"
}
- version: "0.65.1"
+ version: "0.69.1"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 6
- day: 9
+ month: 11
+ day: 20
}
}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..620ad0a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,89 @@
+[![crates.io](https://img.shields.io/crates/v/bindgen.svg)](https://crates.io/crates/bindgen)
+[![docs.rs](https://docs.rs/bindgen/badge.svg)](https://docs.rs/bindgen/)
+
+# `bindgen`
+
+**`bindgen` automatically generates Rust FFI bindings to C (and some C++) libraries.**
+
+For example, given the C header `doggo.h`:
+
+```c
+typedef struct Doggo {
+ int many;
+ char wow;
+} Doggo;
+
+void eleven_out_of_ten_majestic_af(Doggo* pupper);
+```
+
+`bindgen` produces Rust FFI code allowing you to call into the `doggo` library's
+functions and use its types:
+
+```rust
+/* automatically generated by rust-bindgen 0.99.9 */
+
+#[repr(C)]
+pub struct Doggo {
+ pub many: ::std::os::raw::c_int,
+ pub wow: ::std::os::raw::c_char,
+}
+
+extern "C" {
+ pub fn eleven_out_of_ten_majestic_af(pupper: *mut Doggo);
+}
+```
+
+## Users Guide
+
+[📚 Read the `bindgen` users guide here! 📚](https://rust-lang.github.io/rust-bindgen)
+
+## MSRV
+
+The `bindgen` minimum supported Rust version is **1.60.0**.
+
+The `bindgen-cli` minimum supported Rust version is **1.64.0**.
+
+No MSRV bump policy has been established yet, so MSRV may increase in any release.
+
+The MSRV is the minimum Rust version that can be used to *compile* each crate. However, `bindgen` and `bindgen-cli` can generate bindings that are compatible with Rust versions below the current MSRV.
+
+Most of the time, the `bindgen-cli` crate will have a more recent MSRV than `bindgen` as crates such as `clap` require it.
+
+## API Reference
+
+[API reference documentation is on docs.rs](https://docs.rs/bindgen)
+
+## Environment Variables
+
+In addition to the [library API](https://docs.rs/bindgen) and [executable command-line API][bindgen-cmdline],
+`bindgen` can be controlled through environment variables.
+
+End-users should set these environment variables to modify `bindgen`'s behavior without modifying the source code of direct consumers of `bindgen`.
+
+- `BINDGEN_EXTRA_CLANG_ARGS`: extra arguments to pass to `clang`
+ - Arguments are whitespace-separated
+ - Use shell-style quoting to pass through whitespace
+ - Examples:
+ - Specify alternate sysroot: `--sysroot=/path/to/sysroot`
+ - Add include search path with spaces: `-I"/path/with spaces"`
+- `BINDGEN_EXTRA_CLANG_ARGS_<TARGET>`: similar to `BINDGEN_EXTRA_CLANG_ARGS`,
+ but used to set per-target arguments to pass to clang. Useful to set system include
+ directories in a target-specific way in cross-compilation environments with multiple targets.
+ Has precedence over `BINDGEN_EXTRA_CLANG_ARGS`.
+
+Additionally, `bindgen` uses `libclang` to parse C and C++ header files.
+To modify how `bindgen` searches for `libclang`, see the [`clang-sys` documentation][clang-sys-env].
+For more details on how `bindgen` uses `libclang`, see the [`bindgen` users guide][bindgen-book-clang].
+
+## Releases
+
+We don't follow a specific release calendar, but if you need a release please
+file an issue requesting that (ping `@emilio` for increased effectiveness).
+
+## Contributing
+
+[See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md)
+
+[bindgen-cmdline]: https://rust-lang.github.io/rust-bindgen/command-line-usage.html
+[clang-sys-env]: https://github.com/KyleMayes/clang-sys#environment-variables
+[bindgen-book-clang]: https://rust-lang.github.io/rust-bindgen/requirements.html#clang
diff --git a/callbacks.rs b/callbacks.rs
index 5824466..c22ba97 100644
--- a/callbacks.rs
+++ b/callbacks.rs
@@ -99,6 +99,9 @@ pub trait ParseCallbacks: fmt::Debug {
None
}
+ /// This will be called on every header filename passed to (`Builder::header`)[`crate::Builder::header`].
+ fn header_file(&self, _filename: &str) {}
+
/// This will be called on every file inclusion, with the full path of the included file.
fn include_file(&self, _filename: &str) {}
@@ -135,6 +138,27 @@ pub trait ParseCallbacks: fmt::Debug {
fn process_comment(&self, _comment: &str) -> Option<String> {
None
}
+
+ /// Potentially override the visibility of a composite type field.
+ ///
+ /// Caution: This allows overriding standard C++ visibility inferred by
+ /// `respect_cxx_access_specs`.
+ fn field_visibility(
+ &self,
+ _info: FieldInfo<'_>,
+ ) -> Option<crate::FieldVisibilityKind> {
+ None
+ }
+
+ /// Process a function name that as exactly one `va_list` argument
+ /// to be wrapped as a variadic function with the wrapped static function
+ /// feature.
+ ///
+ /// The returned string is new function name.
+ #[cfg(feature = "experimental")]
+ fn wrap_as_variadic_fn(&self, _name: &str) -> Option<String> {
+ None
+ }
}
/// Relevant information about a type to which new derive attributes will be added using
@@ -176,3 +200,14 @@ pub enum ItemKind {
/// A Variable
Var,
}
+
+/// Relevant information about a field for which visibility can be determined using
+/// [`ParseCallbacks::field_visibility`].
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct FieldInfo<'a> {
+ /// The name of the type.
+ pub type_name: &'a str,
+ /// The name of the field.
+ pub field_name: &'a str,
+}
diff --git a/clang.rs b/clang.rs
index 4f8de24..3438bfa 100644
--- a/clang.rs
+++ b/clang.rs
@@ -6,6 +6,8 @@
use crate::ir::context::BindgenContext;
use clang_sys::*;
+use std::cmp;
+
use std::ffi::{CStr, CString};
use std::fmt;
use std::hash::Hash;
@@ -496,6 +498,96 @@ impl Cursor {
}
}
+ /// Traverse all of this cursor's children, sorted by where they appear in source code.
+ ///
+ /// Call the given function on each AST node traversed.
+ pub(crate) fn visit_sorted<Visitor>(
+ &self,
+ ctx: &mut BindgenContext,
+ mut visitor: Visitor,
+ ) where
+ Visitor: FnMut(&mut BindgenContext, Cursor),
+ {
+ // FIXME(#2556): The current source order stuff doesn't account well for different levels
+ // of includes, or includes that show up at the same byte offset because they are passed in
+ // via CLI.
+ const SOURCE_ORDER_ENABLED: bool = false;
+ if !SOURCE_ORDER_ENABLED {
+ return self.visit(|c| {
+ visitor(ctx, c);
+ CXChildVisit_Continue
+ });
+ }
+
+ let mut children = self.collect_children();
+ for child in &children {
+ if child.kind() == CXCursor_InclusionDirective {
+ if let Some(included_file) = child.get_included_file_name() {
+ let location = child.location();
+ let (source_file, _, _, offset) = location.location();
+
+ if let Some(source_file) = source_file.name() {
+ ctx.add_include(source_file, included_file, offset);
+ }
+ }
+ }
+ }
+ children
+ .sort_by(|child1, child2| child1.cmp_by_source_order(child2, ctx));
+ for child in children {
+ visitor(ctx, child);
+ }
+ }
+
+ /// Compare source order of two cursors, considering `#include` directives.
+ ///
+ /// Built-in items provided by the compiler (which don't have a source file),
+ /// are sorted first. Remaining files are sorted by their position in the source file.
+ /// If the items' source files differ, they are sorted by the position of the first
+ /// `#include` for their source file. If no source files are included, `None` is returned.
+ fn cmp_by_source_order(
+ &self,
+ other: &Self,
+ ctx: &BindgenContext,
+ ) -> cmp::Ordering {
+ let (file, _, _, offset) = self.location().location();
+ let (other_file, _, _, other_offset) = other.location().location();
+
+ let (file, other_file) = match (file.name(), other_file.name()) {
+ (Some(file), Some(other_file)) => (file, other_file),
+ // Built-in definitions should come first.
+ (Some(_), None) => return cmp::Ordering::Greater,
+ (None, Some(_)) => return cmp::Ordering::Less,
+ (None, None) => return cmp::Ordering::Equal,
+ };
+
+ if file == other_file {
+ // Both items are in the same source file, compare by byte offset.
+ return offset.cmp(&other_offset);
+ }
+
+ let include_location = ctx.included_file_location(&file);
+ let other_include_location = ctx.included_file_location(&other_file);
+ match (include_location, other_include_location) {
+ (Some((file2, offset2)), _) if file2 == other_file => {
+ offset2.cmp(&other_offset)
+ }
+ (Some(_), None) => cmp::Ordering::Greater,
+ (_, Some((other_file2, other_offset2))) if file == other_file2 => {
+ offset.cmp(&other_offset2)
+ }
+ (None, Some(_)) => cmp::Ordering::Less,
+ (Some((file2, offset2)), Some((other_file2, other_offset2))) => {
+ if file2 == other_file2 {
+ offset2.cmp(&other_offset2)
+ } else {
+ cmp::Ordering::Equal
+ }
+ }
+ (None, None) => cmp::Ordering::Equal,
+ }
+ }
+
/// Collect all of this cursor's children into a vec and return them.
pub(crate) fn collect_children(&self) -> Vec<Cursor> {
let mut children = vec![];
@@ -833,21 +925,6 @@ impl Cursor {
unsafe { clang_isVirtualBase(self.x) != 0 }
}
- // Is this cursor's referent a default constructor?
- pub fn is_default_constructor(&self) -> bool {
- unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 }
- }
-
- // Is this cursor's referent a copy constructor?
- pub fn is_copy_constructor(&self) -> bool {
- unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 }
- }
-
- // Is this cursor's referent a move constructor?
- pub fn is_move_constructor(&self) -> bool {
- unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 }
- }
-
/// Try to evaluate this cursor.
pub(crate) fn evaluate(&self) -> Option<EvalResult> {
EvalResult::new(*self)
@@ -1736,14 +1813,14 @@ impl TranslationUnit {
pub(crate) fn parse(
ix: &Index,
file: &str,
- cmd_args: &[String],
+ cmd_args: &[Box<str>],
unsaved: &[UnsavedFile],
opts: CXTranslationUnit_Flags,
) -> Option<TranslationUnit> {
let fname = CString::new(file).unwrap();
let _c_args: Vec<CString> = cmd_args
.iter()
- .map(|s| CString::new(s.clone()).unwrap())
+ .map(|s| CString::new(s.as_bytes()).unwrap())
.collect();
let c_args: Vec<*const c_char> =
_c_args.iter().map(|s| s.as_ptr()).collect();
@@ -1846,9 +1923,9 @@ pub(crate) struct UnsavedFile {
impl UnsavedFile {
/// Construct a new unsaved file with the given `name` and `contents`.
- pub(crate) fn new(name: String, contents: String) -> UnsavedFile {
- let name = CString::new(name).unwrap();
- let contents = CString::new(contents).unwrap();
+ pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile {
+ let name = CString::new(name.as_bytes()).unwrap();
+ let contents = CString::new(contents.as_bytes()).unwrap();
let x = CXUnsavedFile {
Filename: name.as_ptr(),
Contents: contents.as_ptr(),
diff --git a/codegen/error.rs b/codegen/error.rs
index f38a1c6..82e921d 100644
--- a/codegen/error.rs
+++ b/codegen/error.rs
@@ -12,24 +12,38 @@ pub(crate) enum Error {
/// template specialization).
InstantiationOfOpaqueType,
- /// Type was a reference not a pointer, but we had nowhere to record that fact.
- ReferenceButCouldNotRecord,
+ /// Function ABI is not supported.
+ UnsupportedAbi(&'static str),
+
+ /// The pointer type size does not match the target's pointer size.
+ InvalidPointerSize {
+ ty_name: String,
+ ty_size: usize,
+ ptr_size: usize,
+ },
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str(match *self {
+ match self {
Error::NoLayoutForOpaqueBlob => {
- "Tried to generate an opaque blob, but had no layout"
+ "Tried to generate an opaque blob, but had no layout.".fmt(f)
}
Error::InstantiationOfOpaqueType => {
- "Instantiation of opaque template type or partial template \
- specialization"
+ "Instantiation of opaque template type or partial template specialization."
+ .fmt(f)
+ }
+ Error::UnsupportedAbi(abi) => {
+ write!(
+ f,
+ "{} ABI is not supported by the configured Rust target.",
+ abi
+ )
}
- Error::ReferenceButCouldNotRecord => {
- "Type was a reference in a context where we only expected other types"
+ Error::InvalidPointerSize { ty_name, ty_size, ptr_size } => {
+ write!(f, "The {} pointer type has size {} but the current target's pointer size is {}.", ty_name, ty_size, ptr_size)
}
- })
+ }
}
}
diff --git a/codegen/helpers.rs b/codegen/helpers.rs
index 113e93d..7ef44fe 100644
--- a/codegen/helpers.rs
+++ b/codegen/helpers.rs
@@ -1,11 +1,7 @@
//! Helpers for code generation that don't need macro expansion.
-use crate::ir::comp::SpecialMemberKind;
-use crate::ir::function::Visibility;
+use crate::ir::context::BindgenContext;
use crate::ir::layout::Layout;
-use crate::{ir::context::BindgenContext, BindgenOptions};
-use proc_macro2::{Ident, Span, TokenStream};
-use quote::TokenStreamExt;
pub(crate) mod attributes {
use proc_macro2::{Ident, Span, TokenStream};
@@ -79,202 +75,29 @@ pub(crate) mod attributes {
}
}
-pub trait CppSemanticAttributeCreator {
- fn do_add(&mut self, ts: TokenStream);
- fn is_enabled(&self) -> bool;
-
- fn add(&mut self, tokens: TokenStream) {
- if self.is_enabled() {
- self.do_add(quote! {
- #[cpp_semantics(#tokens)]
- })
- }
- }
-
- fn add_ident(&mut self, desc: &str) {
- if self.is_enabled() {
- let id = Ident::new(desc, Span::call_site());
- self.add(quote! { #id })
- }
- }
-
- fn special_member(&mut self, kind: SpecialMemberKind) {
- let kind_str = match kind {
- SpecialMemberKind::DefaultConstructor => "default_ctor",
- SpecialMemberKind::CopyConstructor => "copy_ctor",
- SpecialMemberKind::MoveConstructor => "move_ctor",
- SpecialMemberKind::Destructor => "dtor",
- SpecialMemberKind::AssignmentOperator => "assignment_operator",
- };
- self.add(quote! {
- special_member(#kind_str)
- })
- }
-
- fn original_name(&mut self, name: &str) {
- self.add(quote! {
- original_name(#name)
- })
- }
-
- fn ret_type_reference(&mut self) {
- self.add_ident("ret_type_reference")
- }
-
- fn ret_type_rvalue_reference(&mut self) {
- self.add_ident("ret_type_rvalue_reference")
- }
-
- fn arg_type_reference(&mut self, arg_name: &Ident) {
- self.add(quote! {
- arg_type_reference(#arg_name)
- })
- }
-
- fn field_type_reference(&mut self) {
- self.add_ident("reference")
- }
-
- fn field_type_rvalue_reference(&mut self) {
- self.add_ident("rvalue_reference")
- }
-
- fn is_virtual(&mut self) {
- self.add_ident("bindgen_virtual")
- }
-
- fn arg_type_rvalue_reference(&mut self, arg_name: &Ident) {
- self.add(quote! {
- arg_type_rvalue_reference(#arg_name)
- })
- }
-
- fn is_pure_virtual(&mut self) {
- self.add_ident("pure_virtual")
- }
-
- fn visibility(&mut self, visibility: Visibility) {
- match visibility {
- Visibility::Protected => self.add_ident("visibility_protected"),
- Visibility::Private => self.add_ident("visibility_private"),
- _ => {}
- }
- }
-
- fn incomprehensible_param_in_arg_or_return(&mut self) {
- self.add_ident("incomprehensible_param_in_arg_or_return")
- }
-
- fn discards_template_param(&mut self) {
- self.add_ident("unused_template_param")
- }
-
- fn deleted_fn(&mut self) {
- self.add_ident("deleted")
- }
-
- fn defaulted_fn(&mut self) {
- self.add_ident("defaulted")
- }
-
- fn layout(&mut self, layout: &Layout) {
- let sz = ast_ty::int_expr(layout.size as i64);
- let align = ast_ty::int_expr(layout.align as i64);
- let packed = if layout.packed {
- quote! { true }
- } else {
- quote! { false }
- };
- self.add(quote! {
- layout(#sz, #align, #packed)
- })
- }
-}
-
-pub struct CppSemanticAttributeAdder<'a> {
- enabled: bool,
- attrs: &'a mut Vec<TokenStream>,
-}
-
-impl<'a> CppSemanticAttributeAdder<'a> {
- pub(crate) fn new(
- opts: &BindgenOptions,
- attrs: &'a mut Vec<TokenStream>,
- ) -> Self {
- Self {
- enabled: opts.cpp_semantic_attributes,
- attrs,
- }
- }
-}
-
-impl<'a> CppSemanticAttributeCreator for CppSemanticAttributeAdder<'a> {
- fn do_add(&mut self, ts: TokenStream) {
- self.attrs.push(ts)
- }
-
- fn is_enabled(&self) -> bool {
- self.enabled
- }
-}
-
-pub struct CppSemanticAttributeSingle {
- enabled: bool,
- attr: TokenStream,
-}
-
-impl CppSemanticAttributeSingle {
- pub(crate) fn new(opts: &BindgenOptions) -> Self {
- Self {
- enabled: opts.cpp_semantic_attributes,
- attr: quote! {},
- }
- }
-
- pub(crate) fn result(self) -> TokenStream {
- self.attr
- }
-}
-
-impl CppSemanticAttributeCreator for CppSemanticAttributeSingle {
- fn do_add(&mut self, ts: TokenStream) {
- self.attr = ts;
- }
-
- fn is_enabled(&self) -> bool {
- self.enabled
- }
-}
-
/// Generates a proper type for a field or type with a given `Layout`, that is,
/// a type with the correct size and alignment restrictions.
-pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
+pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type {
let opaque = layout.opaque();
// FIXME(emilio, #412): We fall back to byte alignment, but there are
// some things that legitimately are more than 8-byte aligned.
//
// Eventually we should be able to `unwrap` here, but...
- let ty_name = match opaque.known_rust_type_for_array(ctx) {
+ let ty = match opaque.known_rust_type_for_array(ctx) {
Some(ty) => ty,
None => {
warn!("Found unknown alignment on code generation!");
- "u8"
+ syn::parse_quote! { u8 }
}
};
- let ty_name = Ident::new(ty_name, Span::call_site());
-
let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
if data_len == 1 {
- quote! {
- #ty_name
- }
+ ty
} else {
- quote! {
- [ #ty_name ; #data_len ]
- }
+ syn::parse_quote! { [ #ty ; #data_len ] }
}
}
@@ -282,80 +105,118 @@ pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
pub(crate) fn integer_type(
ctx: &BindgenContext,
layout: Layout,
-) -> Option<TokenStream> {
- let name = Layout::known_type_for_size(ctx, layout.size)?;
- let name = Ident::new(name, Span::call_site());
- Some(quote! { #name })
+) -> Option<syn::Type> {
+ Layout::known_type_for_size(ctx, layout.size)
}
/// Generates a bitfield allocation unit type for a type with the given `Layout`.
-pub(crate) fn bitfield_unit(
- ctx: &BindgenContext,
- layout: Layout,
-) -> TokenStream {
- let mut tokens = quote! {};
+pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
+ let size = layout.size;
+ let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> };
if ctx.options().enable_cxx_namespaces {
- tokens.append_all(quote! { root:: });
+ return syn::parse_quote! { root::#ty };
}
- let size = layout.size;
- tokens.append_all(quote! {
- __BindgenBitfieldUnit<[u8; #size]>
- });
-
- tokens
+ ty
}
pub(crate) mod ast_ty {
use crate::ir::context::BindgenContext;
use crate::ir::function::FunctionSig;
use crate::ir::layout::Layout;
- use crate::ir::ty::FloatKind;
+ use crate::ir::ty::{FloatKind, IntKind};
use proc_macro2::{self, TokenStream};
use std::str::FromStr;
- pub(crate) fn c_void(ctx: &BindgenContext) -> TokenStream {
+ pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type {
// ctypes_prefix takes precedence
match ctx.options().ctypes_prefix {
Some(ref prefix) => {
let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
- quote! {
- #prefix::c_void
- }
+ syn::parse_quote! { #prefix::c_void }
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features.core_ffi_c_void
{
- quote! { ::core::ffi::c_void }
+ syn::parse_quote! { ::core::ffi::c_void }
} else {
- quote! { ::std::os::raw::c_void }
+ syn::parse_quote! { ::std::os::raw::c_void }
}
}
}
}
- pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
+ pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type {
let ident = ctx.rust_ident_raw(name);
match ctx.options().ctypes_prefix {
Some(ref prefix) => {
let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
- quote! {
- #prefix::#ident
- }
+ syn::parse_quote! { #prefix::#ident }
}
None => {
if ctx.options().use_core &&
ctx.options().rust_features().core_ffi_c
{
- quote! {
- ::core::ffi::#ident
- }
+ syn::parse_quote! { ::core::ffi::#ident }
} else {
- quote! {
- ::std::os::raw::#ident
- }
+ syn::parse_quote! { ::std::os::raw::#ident }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn int_kind_rust_type(
+ ctx: &BindgenContext,
+ ik: IntKind,
+ layout: Option<Layout>,
+ ) -> syn::Type {
+ match ik {
+ IntKind::Bool => syn::parse_quote! { bool },
+ IntKind::Char { .. } => raw_type(ctx, "c_char"),
+ IntKind::SChar => raw_type(ctx, "c_schar"),
+ IntKind::UChar => raw_type(ctx, "c_uchar"),
+ IntKind::Short => raw_type(ctx, "c_short"),
+ IntKind::UShort => raw_type(ctx, "c_ushort"),
+ IntKind::Int => raw_type(ctx, "c_int"),
+ IntKind::UInt => raw_type(ctx, "c_uint"),
+ IntKind::Long => raw_type(ctx, "c_long"),
+ IntKind::ULong => raw_type(ctx, "c_ulong"),
+ IntKind::LongLong => raw_type(ctx, "c_longlong"),
+ IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
+ IntKind::WChar => {
+ let layout =
+ layout.expect("Couldn't compute wchar_t's layout?");
+ Layout::known_type_for_size(ctx, layout.size)
+ .expect("Non-representable wchar_t?")
+ }
+
+ IntKind::I8 => syn::parse_quote! { i8 },
+ IntKind::U8 => syn::parse_quote! { u8 },
+ IntKind::I16 => syn::parse_quote! { i16 },
+ IntKind::U16 => syn::parse_quote! { u16 },
+ IntKind::I32 => syn::parse_quote! { i32 },
+ IntKind::U32 => syn::parse_quote! { u32 },
+ IntKind::I64 => syn::parse_quote! { i64 },
+ IntKind::U64 => syn::parse_quote! { u64 },
+ IntKind::Custom { name, .. } => {
+ syn::parse_str(name).expect("Invalid integer type.")
+ }
+ IntKind::U128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { u128 }
+ } else {
+ // Best effort thing, but wrong alignment
+ // unfortunately.
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ IntKind::I128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { i128 }
+ } else {
+ syn::parse_quote! { [u64; 2] }
}
}
}
@@ -365,26 +226,26 @@ pub(crate) mod ast_ty {
ctx: &BindgenContext,
fk: FloatKind,
layout: Option<Layout>,
- ) -> TokenStream {
+ ) -> syn::Type {
// TODO: we probably should take the type layout into account more
// often?
//
// Also, maybe this one shouldn't be the default?
match (fk, ctx.options().convert_floats) {
- (FloatKind::Float, true) => quote! { f32 },
- (FloatKind::Double, true) => quote! { f64 },
+ (FloatKind::Float, true) => syn::parse_quote! { f32 },
+ (FloatKind::Double, true) => syn::parse_quote! { f64 },
(FloatKind::Float, false) => raw_type(ctx, "c_float"),
(FloatKind::Double, false) => raw_type(ctx, "c_double"),
(FloatKind::LongDouble, _) => {
match layout {
Some(layout) => {
match layout.size {
- 4 => quote! { f32 },
- 8 => quote! { f64 },
+ 4 => syn::parse_quote! { f32 },
+ 8 => syn::parse_quote! { f64 },
// TODO(emilio): If rust ever gains f128 we should
// use it here and below.
_ => super::integer_type(ctx, layout)
- .unwrap_or(quote! { f64 }),
+ .unwrap_or(syn::parse_quote! { f64 }),
}
}
None => {
@@ -392,15 +253,15 @@ pub(crate) mod ast_ty {
false,
"How didn't we know the layout for a primitive type?"
);
- quote! { f64 }
+ syn::parse_quote! { f64 }
}
}
}
(FloatKind::Float128, _) => {
if ctx.options().rust_features.i128_and_u128 {
- quote! { u128 }
+ syn::parse_quote! { u128 }
} else {
- quote! { [u64; 2] }
+ syn::parse_quote! { [u64; 2] }
}
}
}
@@ -418,12 +279,6 @@ pub(crate) mod ast_ty {
quote!(#val)
}
- pub(crate) fn byte_array_expr(bytes: &[u8]) -> TokenStream {
- let mut bytes: Vec<_> = bytes.to_vec();
- bytes.push(0);
- quote! { [ #(#bytes),* ] }
- }
-
pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
string.push('\0');
let b = proc_macro2::Literal::byte_string(string.as_bytes());
diff --git a/codegen/mod.rs b/codegen/mod.rs
index 41f6e3a..8e13606 100644
--- a/codegen/mod.rs
+++ b/codegen/mod.rs
@@ -1,5 +1,6 @@
mod dyngen;
-mod error;
+pub(crate) mod error;
+
mod helpers;
mod impl_debug;
mod impl_partialeq;
@@ -19,11 +20,8 @@ use self::struct_layout::StructLayoutTracker;
use super::BindgenOptions;
-use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind};
-use crate::codegen::helpers::{
- CppSemanticAttributeAdder, CppSemanticAttributeCreator,
- CppSemanticAttributeSingle,
-};
+use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind};
+use crate::codegen::error::Error;
use crate::ir::analysis::{HasVtable, Sizedness};
use crate::ir::annotations::{
Annotations, FieldAccessorKind, FieldVisibilityKind,
@@ -40,7 +38,7 @@ use crate::ir::derive::{
use crate::ir::dot;
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use crate::ir::function::{
- Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
+ ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
};
use crate::ir::int::IntKind;
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
@@ -61,9 +59,10 @@ use crate::{Entry, HashMap, HashSet};
use std::borrow::Cow;
use std::cell::Cell;
use std::collections::VecDeque;
+use std::ffi::CStr;
use std::fmt::{self, Write};
use std::ops;
-use std::str::FromStr;
+use std::str::{self, FromStr};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CodegenError {
@@ -224,6 +223,11 @@ impl From<DerivableTraits> for Vec<&'static str> {
}
}
+struct WrapAsVariadic {
+ new_name: String,
+ idx_of_va_list_arg: usize,
+}
+
struct CodegenResult<'a> {
items: Vec<proc_macro2::TokenStream>,
dynamic_items: DynamicItems,
@@ -272,7 +276,9 @@ struct CodegenResult<'a> {
/// that name. This lets us give each overload a unique suffix.
overload_counters: HashMap<String, u32>,
- items_to_serialize: Vec<ItemId>,
+ /// List of items to serialize. With optionally the argument for the wrap as
+ /// variadic transformation to be applied.
+ items_to_serialize: Vec<(ItemId, Option<WrapAsVariadic>)>,
}
impl<'a> CodegenResult<'a> {
@@ -387,45 +393,44 @@ impl<'a> ops::DerefMut for CodegenResult<'a> {
/// A trait to convert a rust type into a pointer, optionally const, to the same
/// type.
trait ToPtr {
- fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream;
+ fn to_ptr(self, is_const: bool) -> syn::Type;
}
-impl ToPtr for proc_macro2::TokenStream {
- fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream {
+impl ToPtr for syn::Type {
+ fn to_ptr(self, is_const: bool) -> syn::Type {
if is_const {
- quote! { *const #self }
+ syn::parse_quote! { *const #self }
} else {
- quote! { *mut #self }
+ syn::parse_quote! { *mut #self }
}
}
}
-/// An extension trait for `proc_macro2::TokenStream` that lets us append any implicit
+/// An extension trait for `syn::Type` that lets us append any implicit
/// template parameters that exist for some type, if necessary.
-trait AppendImplicitTemplateParams {
- fn append_implicit_template_params(
- &mut self,
+trait WithImplicitTemplateParams {
+ fn with_implicit_template_params(
+ self,
ctx: &BindgenContext,
item: &Item,
- );
+ ) -> Self;
}
-impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
- fn append_implicit_template_params(
- &mut self,
+impl WithImplicitTemplateParams for syn::Type {
+ fn with_implicit_template_params(
+ self,
ctx: &BindgenContext,
item: &Item,
- ) {
+ ) -> Self {
let item = item.id().into_resolver().through_type_refs().resolve(ctx);
- match *item.expect_type().kind() {
+ let params = match *item.expect_type().kind() {
TypeKind::UnresolvedTypeRef(..) => {
unreachable!("already resolved unresolved type refs")
}
TypeKind::ResolvedTypeRef(..) => {
unreachable!("we resolved item through type refs")
}
-
// None of these types ever have implicit template parameters.
TypeKind::Void |
TypeKind::NullPtr |
@@ -441,23 +446,25 @@ impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
TypeKind::Enum(..) |
TypeKind::ObjCId |
TypeKind::ObjCSel |
- TypeKind::TemplateInstantiation(..) => return,
- _ => {}
- }
+ TypeKind::TemplateInstantiation(..) => None,
+ _ => {
+ let params = item.used_template_params(ctx);
+ if params.is_empty() {
+ None
+ } else {
+ Some(params.into_iter().map(|p| {
+ p.try_to_rust_ty(ctx, &()).expect(
+ "template params cannot fail to be a rust type",
+ )
+ }))
+ }
+ }
+ };
- let (used_template_params, _) = item.used_template_params(ctx);
- let params: Vec<_> = used_template_params
- .iter()
- .map(|p| {
- p.try_to_rust_ty(ctx, &())
- .expect("template params cannot fail to be a rust type")
- .ignore_annotations()
- })
- .collect();
- if !params.is_empty() {
- self.append_all(quote! {
- < #( #params ),* >
- });
+ if let Some(params) = params {
+ syn::parse_quote! { #self<#(#params),*> }
+ } else {
+ self
}
}
}
@@ -595,7 +602,10 @@ impl CodeGenerator for Module {
let inner_items = result.inner(|result| {
result.push(root_import(ctx, item));
- let path = item.namespace_aware_canonical_path(ctx).join("::");
+ let path = item
+ .namespace_aware_canonical_path(ctx)
+ .join("::")
+ .into_boxed_str();
if let Some(raw_lines) = ctx.options().module_lines.get(&path) {
for raw_line in raw_lines {
found_any = true;
@@ -667,10 +677,8 @@ impl CodeGenerator for Var {
attrs.push(attributes::doc(comment));
}
- let ty = self
- .ty()
- .to_rust_ty_or_opaque(ctx, &())
- .ignore_annotations();
+ let var_ty = self.ty();
+ let ty = var_ty.to_rust_ty_or_opaque(ctx, &());
if let Some(val) = self.val() {
match *val {
@@ -681,8 +689,7 @@ impl CodeGenerator for Var {
});
}
VarType::Int(val) => {
- let int_kind = self
- .ty()
+ let int_kind = var_ty
.into_resolver()
.through_type_aliases()
.through_type_refs()
@@ -701,41 +708,48 @@ impl CodeGenerator for Var {
});
}
VarType::String(ref bytes) => {
- // Account the trailing zero.
- //
+ let prefix = ctx.trait_prefix();
+
+ let options = ctx.options();
+ let rust_features = options.rust_features;
+
+ let mut cstr_bytes = bytes.clone();
+ cstr_bytes.push(0);
+ let len = proc_macro2::Literal::usize_unsuffixed(
+ cstr_bytes.len(),
+ );
+
// TODO: Here we ignore the type we just made up, probably
// we should refactor how the variable type and ty ID work.
- let len = bytes.len() + 1;
- let ty = quote! {
- [u8; #len]
- };
+ let array_ty = quote! { [u8; #len] };
+ let cstr_ty = quote! { ::#prefix::ffi::CStr };
- match String::from_utf8(bytes.clone()) {
- Ok(string) => {
- let cstr = helpers::ast_ty::cstr_expr(string);
- if ctx
- .options()
- .rust_features
- .static_lifetime_elision
- {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : &#ty = #cstr ;
- });
- } else {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : &'static #ty = #cstr ;
- });
- }
- }
- Err(..) => {
- let bytes = helpers::ast_ty::byte_array_expr(bytes);
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #bytes ;
- });
+ let bytes = proc_macro2::Literal::byte_string(&cstr_bytes);
+
+ if options.generate_cstr &&
+ rust_features.const_cstr &&
+ CStr::from_bytes_with_nul(&cstr_bytes).is_ok()
+ {
+ result.push(quote! {
+ #(#attrs)*
+ #[allow(unsafe_code)]
+ pub const #canonical_ident: &#cstr_ty = unsafe {
+ #cstr_ty::from_bytes_with_nul_unchecked(#bytes)
+ };
+ });
+ } else {
+ let lifetime = if rust_features.static_lifetime_elision
+ {
+ None
+ } else {
+ Some(quote! { 'static })
}
+ .into_iter();
+
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ;
+ });
}
}
VarType::Float(f) => {
@@ -912,8 +926,7 @@ impl CodeGenerator for Type {
return;
}
- let (mut outer_params, has_unused_template_args) =
- item.used_template_params(ctx);
+ let mut outer_params = item.used_template_params(ctx);
let is_opaque = item.is_opaque(ctx, &());
let inner_rust_type = if is_opaque {
@@ -923,14 +936,10 @@ impl CodeGenerator for Type {
// Its possible that we have better layout information than
// the inner type does, so fall back to an opaque blob based
// on our layout if converting the inner item fails.
- let (mut inner_ty, _) = inner_item
+ inner_item
.try_to_rust_ty_or_opaque(ctx, &())
- .map(|ty| ty.into_outer_type())
- .unwrap_or_else(|_| {
- (self.to_opaque(ctx, item), RustTyAnnotation::None)
- });
- inner_ty.append_implicit_template_params(ctx, inner_item);
- inner_ty
+ .unwrap_or_else(|_| self.to_opaque(ctx, item))
+ .with_implicit_template_params(ctx, inner_item)
};
{
@@ -963,18 +972,6 @@ impl CodeGenerator for Type {
} else {
quote! {}
};
- let mut semantic_annotations =
- CppSemanticAttributeSingle::new(ctx.options());
- // We are handling (essentially) type X = Y;
- // We want to denote only if X has unused template params, e.g.
- // type X<A> = Y;
- // We don't want to note whether Y has unused template params, e.g.
- // type X = Y<B>
- // because that information will be recorded against the definition of Y.
- if has_unused_template_args {
- semantic_annotations.discards_template_param();
- }
- tokens.append_all(semantic_annotations.result());
let alias_style = if ctx.options().type_alias.matches(&name) {
AliasVariation::TypeAlias
@@ -988,9 +985,8 @@ impl CodeGenerator for Type {
// We prefer using `pub use` over `pub type` because of:
// https://github.com/rust-lang/rust/issues/26264
- // These are the only characters allowed in simple
- // paths, eg `good::dogs::Bront`.
- if inner_rust_type.to_string().chars().all(|c| matches!(c, 'A'..='Z' | 'a'..='z' | '0'..='9' | ':' | '_' | ' ')) && outer_params.is_empty() &&
+ if matches!(inner_rust_type, syn::Type::Path(_)) &&
+ outer_params.is_empty() &&
!is_opaque &&
alias_style == AliasVariation::TypeAlias &&
inner_item.expect_type().canonical_type(ctx).is_enum()
@@ -1007,21 +1003,8 @@ impl CodeGenerator for Type {
return;
}
- let mut attributes = Vec::new();
- if let Some(original_name) = item.original_name(ctx) {
- if name != original_name {
- let mut semantic_annotations =
- CppSemanticAttributeAdder::new(
- ctx.options(),
- &mut attributes,
- );
- semantic_annotations.original_name(&original_name);
- }
- }
-
tokens.append_all(match alias_style {
AliasVariation::TypeAlias => quote! {
- #( #attributes )*
pub type #rust_name
},
AliasVariation::NewType | AliasVariation::NewTypeDeref => {
@@ -1068,7 +1051,7 @@ impl CodeGenerator for Type {
.map(|p| {
p.try_to_rust_ty(ctx, &()).expect(
"type parameters can always convert to rust ty OK",
- ).ignore_annotations()
+ )
})
.collect();
@@ -1184,8 +1167,8 @@ impl<'a> CodeGenerator for Vtable<'a> {
// FIXME: Need to account for overloading with times_seen (separately from regular function path).
let function_name = ctx.rust_ident(function_name);
- let (mut args, _) = utils::fnsig_arguments(ctx, signature);
- let (ret, _) = utils::fnsig_return_ty(ctx, signature);
+ let mut args = utils::fnsig_arguments(ctx, signature);
+ let ret = utils::fnsig_return_ty(ctx, signature);
args[0] = if m.is_const() {
quote! { this: *const #class_ident }
@@ -1230,12 +1213,9 @@ impl<'a> TryToRustTy for Vtable<'a> {
&self,
ctx: &BindgenContext,
_: &(),
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
let name = ctx.rust_ident(self.canonical_name(ctx));
- Ok(quote! {
- #name
- }
- .into())
+ Ok(syn::parse_quote! { #name })
}
}
@@ -1285,8 +1265,7 @@ impl CodeGenerator for TemplateInstantiation {
let fn_name = ctx.rust_ident_raw(fn_name);
let prefix = ctx.trait_prefix();
- let ident =
- item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
+ let ident = item.to_rust_ty_or_opaque(ctx, &());
let size_of_expr = quote! {
::#prefix::mem::size_of::<#ident>()
};
@@ -1322,6 +1301,7 @@ trait FieldCodegen<'a> {
visibility_kind: FieldVisibilityKind,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
+ parent_item: &Item,
result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
@@ -1341,6 +1321,7 @@ impl<'a> FieldCodegen<'a> for Field {
visibility_kind: FieldVisibilityKind,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
+ parent_item: &Item,
result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
@@ -1357,6 +1338,7 @@ impl<'a> FieldCodegen<'a> for Field {
visibility_kind,
accessor_kind,
parent,
+ parent_item,
result,
struct_layout,
fields,
@@ -1370,6 +1352,7 @@ impl<'a> FieldCodegen<'a> for Field {
visibility_kind,
accessor_kind,
parent,
+ parent_item,
result,
struct_layout,
fields,
@@ -1384,28 +1367,22 @@ impl<'a> FieldCodegen<'a> for Field {
fn wrap_union_field_if_needed(
ctx: &BindgenContext,
struct_layout: &StructLayoutTracker,
- ty: proc_macro2::TokenStream,
+ ty: syn::Type,
result: &mut CodegenResult,
-) -> proc_macro2::TokenStream {
+) -> syn::Type {
if struct_layout.is_rust_union() {
if struct_layout.can_copy_union_fields() {
ty
} else {
let prefix = ctx.trait_prefix();
- quote! {
- ::#prefix::mem::ManuallyDrop<#ty>
- }
+ syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty> }
}
} else {
result.saw_bindgen_union();
if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#ty>
- }
+ syn::parse_quote! { root::__BindgenUnionField<#ty> }
} else {
- quote! {
- __BindgenUnionField<#ty>
- }
+ syn::parse_quote! { __BindgenUnionField<#ty> }
}
}
}
@@ -1419,6 +1396,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
parent_visibility_kind: FieldVisibilityKind,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
+ parent_item: &Item,
result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
@@ -1435,9 +1413,10 @@ impl<'a> FieldCodegen<'a> for FieldData {
let field_item =
self.ty().into_resolver().through_type_refs().resolve(ctx);
let field_ty = field_item.expect_type();
- let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
- let (mut ty, ty_annotations) = ty.into_outer_type();
- ty.append_implicit_template_params(ctx, field_item);
+ let ty = self
+ .ty()
+ .to_rust_ty_or_opaque(ctx, &())
+ .with_implicit_template_params(ctx, field_item);
// NB: If supported, we use proper `union` types.
let ty = if parent.is_union() {
@@ -1445,17 +1424,12 @@ impl<'a> FieldCodegen<'a> for FieldData {
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
result.saw_incomplete_array();
- let inner =
- item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
+ let inner = item.to_rust_ty_or_opaque(ctx, &());
if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__IncompleteArrayField<#inner>
- }
+ syn::parse_quote! { root::__IncompleteArrayField<#inner> }
} else {
- quote! {
- __IncompleteArrayField<#inner>
- }
+ syn::parse_quote! { __IncompleteArrayField<#inner> }
}
} else {
ty
@@ -1473,10 +1447,11 @@ impl<'a> FieldCodegen<'a> for FieldData {
.name()
.map(|name| ctx.rust_mangle(name).into_owned())
.expect("Each field should have a name in codegen!");
- let field_ident = ctx.rust_ident_raw(field_name.as_str());
+ let field_name = field_name.as_str();
+ let field_ident = ctx.rust_ident_raw(field_name);
if let Some(padding_field) =
- struct_layout.saw_field(&field_name, field_ty, self.offset())
+ struct_layout.saw_field(field_name, field_ty, self.offset())
{
fields.extend(Some(padding_field));
}
@@ -1484,39 +1459,31 @@ impl<'a> FieldCodegen<'a> for FieldData {
let visibility = compute_visibility(
ctx,
self.is_public(),
- Some(self.annotations()),
+ ctx.options().last_callback(|cb| {
+ cb.field_visibility(FieldInfo {
+ type_name: &parent_item.canonical_name(ctx),
+ field_name,
+ })
+ }),
+ self.annotations(),
parent_visibility_kind,
);
let accessor_kind =
self.annotations().accessor_kind().unwrap_or(accessor_kind);
- let mut attributes = Vec::new();
- let mut csaa =
- CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
- match ty_annotations {
- RustTyAnnotation::Reference => csaa.field_type_reference(),
- RustTyAnnotation::RValueReference => {
- csaa.field_type_rvalue_reference()
- }
- _ => {}
- };
-
match visibility {
FieldVisibilityKind::Private => {
field.append_all(quote! {
- #(#attributes),*
#field_ident : #ty ,
});
}
FieldVisibilityKind::PublicCrate => {
field.append_all(quote! {
- #(#attributes),*
pub(crate) #field_ident : #ty ,
});
}
FieldVisibilityKind::Public => {
field.append_all(quote! {
- #(#attributes),*
pub #field_ident : #ty ,
});
}
@@ -1532,7 +1499,6 @@ impl<'a> FieldCodegen<'a> for FieldData {
let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name));
let mutable_getter_name =
ctx.rust_ident_raw(format!("get_{}_mut", field_name));
- let field_name = ctx.rust_ident_raw(field_name);
methods.extend(Some(match accessor_kind {
FieldAccessorKind::None => unreachable!(),
@@ -1540,12 +1506,12 @@ impl<'a> FieldCodegen<'a> for FieldData {
quote! {
#[inline]
pub fn #getter_name(&self) -> & #ty {
- &self.#field_name
+ &self.#field_ident
}
#[inline]
pub fn #mutable_getter_name(&mut self) -> &mut #ty {
- &mut self.#field_name
+ &mut self.#field_ident
}
}
}
@@ -1553,12 +1519,12 @@ impl<'a> FieldCodegen<'a> for FieldData {
quote! {
#[inline]
pub unsafe fn #getter_name(&self) -> & #ty {
- &self.#field_name
+ &self.#field_ident
}
#[inline]
pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty {
- &mut self.#field_name
+ &mut self.#field_ident
}
}
}
@@ -1566,7 +1532,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
quote! {
#[inline]
pub fn #getter_name(&self) -> & #ty {
- &self.#field_name
+ &self.#field_ident
}
}
}
@@ -1651,27 +1617,28 @@ fn access_specifier(
fn compute_visibility(
ctx: &BindgenContext,
is_declared_public: bool,
- annotations: Option<&Annotations>,
+ callback_override: Option<FieldVisibilityKind>,
+ annotations: &Annotations,
default_kind: FieldVisibilityKind,
) -> FieldVisibilityKind {
- match (
- is_declared_public,
- ctx.options().respect_cxx_access_specs,
- annotations.and_then(|e| e.visibility_kind()),
- ) {
- (true, true, annotated_visibility) => {
- // declared as public, cxx specs are respected
- annotated_visibility.unwrap_or(FieldVisibilityKind::Public)
- }
- (false, true, annotated_visibility) => {
- // declared as private, cxx specs are respected
- annotated_visibility.unwrap_or(FieldVisibilityKind::Private)
- }
- (_, false, annotated_visibility) => {
- // cxx specs are not respected, declaration does not matter.
- annotated_visibility.unwrap_or(default_kind)
- }
- }
+ callback_override
+ .or_else(|| annotations.visibility_kind())
+ .unwrap_or_else(|| {
+ match (is_declared_public, ctx.options().respect_cxx_access_specs) {
+ (true, true) => {
+ // declared as public, cxx specs are respected
+ FieldVisibilityKind::Public
+ }
+ (false, true) => {
+ // declared as private, cxx specs are respected
+ FieldVisibilityKind::Private
+ }
+ (_, false) => {
+ // cxx specs are not respected, declaration does not matter.
+ default_kind
+ }
+ }
+ })
}
impl<'a> FieldCodegen<'a> for BitfieldUnit {
@@ -1683,6 +1650,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
visibility_kind: FieldVisibilityKind,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
+ parent_item: &Item,
result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
fields: &mut F,
@@ -1742,7 +1710,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
// the 32 items limitation.
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
- let mut all_fields_declared_as_public = true;
+ let mut unit_visibility = visibility_kind;
for bf in self.bitfields() {
// Codegen not allowed for anonymous bitfields
if bf.name().is_none() {
@@ -1755,19 +1723,27 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
continue;
}
- all_fields_declared_as_public &= bf.is_public();
let mut bitfield_representable_as_int = true;
+ let mut bitfield_visibility = visibility_kind;
bf.codegen(
ctx,
visibility_kind,
accessor_kind,
parent,
+ parent_item,
result,
struct_layout,
fields,
methods,
- (&unit_field_name, &mut bitfield_representable_as_int),
+ (
+ &unit_field_name,
+ &mut bitfield_representable_as_int,
+ &mut bitfield_visibility,
+ ),
);
+ if bitfield_visibility < unit_visibility {
+ unit_visibility = bitfield_visibility;
+ }
// Generating a constructor requires the bitfield to be representable as an integer.
if !bitfield_representable_as_int {
@@ -1778,9 +1754,8 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
let param_name = bitfield_getter_name(ctx, bf);
let bitfield_ty_item = ctx.resolve_item(bf.ty());
let bitfield_ty = bitfield_ty_item.expect_type();
- let bitfield_ty = bitfield_ty
- .to_rust_ty_or_opaque(ctx, bitfield_ty_item)
- .ignore_annotations();
+ let bitfield_ty =
+ bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
ctor_params.push(quote! {
#param_name : #bitfield_ty
@@ -1788,13 +1763,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
}
- let visibility_kind = compute_visibility(
- ctx,
- all_fields_declared_as_public,
- None,
- visibility_kind,
- );
- let access_spec = access_specifier(visibility_kind);
+ let access_spec = access_specifier(unit_visibility);
let field = quote! {
#access_spec #unit_field_ident : #field_ty ,
@@ -1835,7 +1804,7 @@ fn bitfield_setter_name(
}
impl<'a> FieldCodegen<'a> for Bitfield {
- type Extra = (&'a str, &'a mut bool);
+ type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind);
fn codegen<F, M>(
&self,
@@ -1843,11 +1812,16 @@ impl<'a> FieldCodegen<'a> for Bitfield {
visibility_kind: FieldVisibilityKind,
_accessor_kind: FieldAccessorKind,
parent: &CompInfo,
+ parent_item: &Item,
_result: &mut CodegenResult,
struct_layout: &mut StructLayoutTracker,
_fields: &mut F,
methods: &mut M,
- (unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool),
+ (unit_field_name, bitfield_representable_as_int, bitfield_visibility): (
+ &'a str,
+ &mut bool,
+ &'a mut FieldVisibilityKind,
+ ),
) where
F: Extend<proc_macro2::TokenStream>,
M: Extend<proc_macro2::TokenStream>,
@@ -1875,20 +1849,28 @@ impl<'a> FieldCodegen<'a> for Bitfield {
}
};
- let bitfield_ty = bitfield_ty
- .to_rust_ty_or_opaque(ctx, bitfield_ty_item)
- .ignore_annotations();
+ let bitfield_ty =
+ bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
let offset = self.offset_into_unit();
let width = self.width() as u8;
- let visibility_kind = compute_visibility(
+ let override_visibility = self.name().and_then(|field_name| {
+ ctx.options().last_callback(|cb| {
+ cb.field_visibility(FieldInfo {
+ type_name: &parent_item.canonical_name(ctx),
+ field_name,
+ })
+ })
+ });
+ *bitfield_visibility = compute_visibility(
ctx,
self.is_public(),
- Some(self.annotations()),
+ override_visibility,
+ self.annotations(),
visibility_kind,
);
- let access_spec = access_specifier(visibility_kind);
+ let access_spec = access_specifier(*bitfield_visibility);
if parent.is_union() && !struct_layout.is_rust_union() {
methods.extend(Some(quote! {
@@ -1982,8 +1964,17 @@ impl CodeGenerator for CompInfo {
// the parent too.
let is_opaque = item.is_opaque(ctx, &());
let mut fields = vec![];
- let mut struct_layout =
- StructLayoutTracker::new(ctx, self, ty, &canonical_name);
+ let visibility = item
+ .annotations()
+ .visibility_kind()
+ .unwrap_or(ctx.options().default_visibility);
+ let mut struct_layout = StructLayoutTracker::new(
+ ctx,
+ self,
+ ty,
+ &canonical_name,
+ visibility,
+ );
if !is_opaque {
if item.has_vtable_ptr(ctx) {
@@ -1993,7 +1984,6 @@ impl CodeGenerator for CompInfo {
let vtable_type = vtable
.try_to_rust_ty(ctx, &())
.expect("vtable to Rust type conversion is infallible")
- .ignore_annotations()
.to_ptr(true);
fields.push(quote! {
@@ -2009,10 +1999,9 @@ impl CodeGenerator for CompInfo {
}
let inner_item = ctx.resolve_item(base.ty);
- let mut inner = inner_item
+ let inner = inner_item
.to_rust_ty_or_opaque(ctx, &())
- .ignore_annotations();
- inner.append_implicit_template_params(ctx, inner_item);
+ .with_implicit_template_params(ctx, inner_item);
let field_name = ctx.rust_ident(&base.field_name);
struct_layout.saw_base(inner_item.expect_type());
@@ -2035,10 +2024,6 @@ impl CodeGenerator for CompInfo {
let mut methods = vec![];
if !is_opaque {
- let visibility = item
- .annotations()
- .visibility_kind()
- .unwrap_or(ctx.options().default_visibility);
let struct_accessor_kind = item
.annotations()
.accessor_kind()
@@ -2049,6 +2034,7 @@ impl CodeGenerator for CompInfo {
visibility,
struct_accessor_kind,
self,
+ item,
result,
&mut struct_layout,
&mut fields,
@@ -2175,9 +2161,7 @@ impl CodeGenerator for CompInfo {
let mut generic_param_names = vec![];
- let (used_template_params, unused_template_params) =
- item.used_template_params(ctx);
- for (idx, ty) in used_template_params.iter().enumerate() {
+ for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
let param = ctx.resolve_type(*ty);
let name = param.name().unwrap();
let ident = ctx.rust_ident(name);
@@ -2221,15 +2205,6 @@ impl CodeGenerator for CompInfo {
} else {
attributes.push(attributes::repr("C"));
}
- let mut semantic_annotations =
- CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
- if unused_template_params {
- semantic_annotations.discards_template_param();
- }
- semantic_annotations.visibility(self.visibility());
- if let Some(layout) = layout {
- semantic_annotations.layout(&layout);
- }
if ctx.options().rust_features().repr_align {
if let Some(explicit) = explicit_align {
@@ -2296,16 +2271,6 @@ impl CodeGenerator for CompInfo {
attributes.push(attributes::derives(&derives))
}
- if let Some(original_name) = item.original_name(ctx) {
- if canonical_name != original_name {
- let mut semantic_annotations = CppSemanticAttributeAdder::new(
- ctx.options(),
- &mut attributes,
- );
- semantic_annotations.original_name(&original_name);
- }
- }
-
if item.must_use(ctx) {
attributes.push(attributes::must_use());
}
@@ -2638,22 +2603,7 @@ impl Method {
_ => panic!("How in the world?"),
};
- let supported_abi = match signature.abi(ctx, Some(&*name)) {
- ClangAbi::Known(Abi::ThisCall) => {
- ctx.options().rust_features().thiscall_abi
- }
- ClangAbi::Known(Abi::Vectorcall) => {
- ctx.options().rust_features().vectorcall_abi
- }
- ClangAbi::Known(Abi::CUnwind) => {
- ctx.options().rust_features().c_unwind_abi
- }
- ClangAbi::Known(Abi::EfiApi) => {
- ctx.options().rust_features().abi_efiapi
- }
- _ => true,
- };
-
+ let supported_abi = signature.abi(ctx, Some(&*name)).is_ok();
if !supported_abi {
return;
}
@@ -2685,9 +2635,8 @@ impl Method {
write!(&mut function_name, "{}", times_seen).unwrap();
}
let function_name = ctx.rust_ident(function_name);
- let (mut args, args_attributes) =
- utils::fnsig_arguments(ctx, signature);
- let (mut ret, ret_attr) = utils::fnsig_return_ty(ctx, signature);
+ let mut args = utils::fnsig_arguments(ctx, signature);
+ let mut ret = utils::fnsig_return_ty(ctx, signature);
if !self.is_static() && !self.is_constructor() {
args[0] = if self.is_const() {
@@ -2763,9 +2712,7 @@ impl Method {
let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*));
- let mut attrs = args_attributes;
- attrs.push(ret_attr);
- attrs.push(attributes::inline());
+ let mut attrs = vec![attributes::inline()];
if signature.must_use() &&
ctx.options().rust_features().must_use_function
@@ -2925,7 +2872,7 @@ impl<'a> EnumBuilder<'a> {
fn new(
name: &'a str,
mut attrs: Vec<proc_macro2::TokenStream>,
- repr: proc_macro2::TokenStream,
+ repr: syn::Type,
enum_variation: EnumVariation,
has_typedef: bool,
) -> Self {
@@ -2994,7 +2941,7 @@ impl<'a> EnumBuilder<'a> {
ctx: &BindgenContext,
variant: &EnumVariant,
mangling_prefix: Option<&str>,
- rust_ty: proc_macro2::TokenStream,
+ rust_ty: syn::Type,
result: &mut CodegenResult<'_>,
is_ty_named: bool,
) -> Self {
@@ -3109,7 +3056,7 @@ impl<'a> EnumBuilder<'a> {
fn build(
self,
ctx: &BindgenContext,
- rust_ty: proc_macro2::TokenStream,
+ rust_ty: syn::Type,
result: &mut CodegenResult<'_>,
) -> proc_macro2::TokenStream {
match self {
@@ -3286,15 +3233,6 @@ impl CodeGenerator for Enum {
let mut attrs = vec![];
- let mut semantic_annotations =
- CppSemanticAttributeAdder::new(ctx.options(), &mut attrs);
- if let Some(original_name) = item.original_name(ctx) {
- if name != original_name {
- semantic_annotations.original_name(&original_name);
- }
- }
- semantic_annotations.visibility(self.visibility);
-
// TODO(emilio): Delegate this to the builders?
match variation {
EnumVariation::Rust { non_exhaustive } => {
@@ -3369,7 +3307,7 @@ impl CodeGenerator for Enum {
// value.
variant_name: &Ident,
referenced_name: &Ident,
- enum_rust_ty: proc_macro2::TokenStream,
+ enum_rust_ty: syn::Type,
result: &mut CodegenResult<'_>,
) {
let constant_name = if enum_.name().is_some() {
@@ -3389,7 +3327,7 @@ impl CodeGenerator for Enum {
});
}
- let repr = repr.to_rust_ty_or_opaque(ctx, item).ignore_annotations();
+ let repr = repr.to_rust_ty_or_opaque(ctx, item);
let has_typedef = ctx.is_enum_typedef_combo(item.id());
let mut builder =
@@ -3397,8 +3335,7 @@ impl CodeGenerator for Enum {
// A map where we keep a value -> variant relation.
let mut seen_values = HashMap::<_, Ident>::default();
- let enum_rust_ty =
- item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
+ let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &());
let is_toplevel = item.is_toplevel(ctx);
// Used to mangle the constants we generate in the unnamed-enum case.
@@ -3685,7 +3622,7 @@ impl std::str::FromStr for NonCopyUnionStyle {
/// Implementors of this trait should provide the `try_get_layout` method to
/// fallibly get this thing's layout, which the provided `try_to_opaque` trait
/// method will use to convert the `Layout` into an opaque blob Rust type.
-trait TryToOpaque {
+pub(crate) trait TryToOpaque {
type Extra;
/// Get the layout for this thing, if one is available.
@@ -3700,9 +3637,9 @@ trait TryToOpaque {
&self,
ctx: &BindgenContext,
extra: &Self::Extra,
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
self.try_get_layout(ctx, extra)
- .map(|layout| helpers::blob(ctx, layout).into())
+ .map(|layout| helpers::blob(ctx, layout))
}
}
@@ -3716,7 +3653,7 @@ trait TryToOpaque {
///
/// Don't implement this directly. Instead implement `TryToOpaque`, and then
/// leverage the blanket impl for this trait.
-trait ToOpaque: TryToOpaque {
+pub(crate) trait ToOpaque: TryToOpaque {
fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) -> Layout {
self.try_get_layout(ctx, extra)
.unwrap_or_else(|_| Layout::for_size(ctx, 1))
@@ -3726,7 +3663,7 @@ trait ToOpaque: TryToOpaque {
&self,
ctx: &BindgenContext,
extra: &Self::Extra,
- ) -> proc_macro2::TokenStream {
+ ) -> syn::Type {
let layout = self.get_layout(ctx, extra);
helpers::blob(ctx, layout)
}
@@ -3741,14 +3678,14 @@ impl<T> ToOpaque for T where T: TryToOpaque {}
/// const-value generic parameters) then the impl should return an `Err`. It
/// should *not* attempt to return an opaque blob with the correct size and
/// alignment. That is the responsibility of the `TryToOpaque` trait.
-trait TryToRustTy {
+pub(crate) trait TryToRustTy {
type Extra;
fn try_to_rust_ty(
&self,
ctx: &BindgenContext,
extra: &Self::Extra,
- ) -> error::Result<RustTy>;
+ ) -> error::Result<syn::Type>;
}
/// Fallible conversion to a Rust type or an opaque blob with the correct size
@@ -3756,14 +3693,14 @@ trait TryToRustTy {
///
/// Don't implement this directly. Instead implement `TryToRustTy` and
/// `TryToOpaque`, and then leverage the blanket impl for this trait below.
-trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque {
+pub(crate) trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque {
type Extra;
fn try_to_rust_ty_or_opaque(
&self,
ctx: &BindgenContext,
extra: &<Self as TryToRustTyOrOpaque>::Extra,
- ) -> error::Result<RustTy>;
+ ) -> error::Result<syn::Type>;
}
impl<E, T> TryToRustTyOrOpaque for T
@@ -3776,10 +3713,10 @@ where
&self,
ctx: &BindgenContext,
extra: &E,
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
self.try_to_rust_ty(ctx, extra).or_else(|_| {
if let Ok(layout) = self.try_get_layout(ctx, extra) {
- Ok(helpers::blob(ctx, layout).into())
+ Ok(helpers::blob(ctx, layout))
} else {
Err(error::Error::NoLayoutForOpaqueBlob)
}
@@ -3804,14 +3741,14 @@ where
/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely
/// we are to get a usable `Layout` even if we can't generate an equivalent Rust
/// type for a C++ construct.
-trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
+pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
type Extra;
fn to_rust_ty_or_opaque(
&self,
ctx: &BindgenContext,
extra: &<Self as ToRustTyOrOpaque>::Extra,
- ) -> RustTy;
+ ) -> syn::Type;
}
impl<E, T> ToRustTyOrOpaque for T
@@ -3820,9 +3757,13 @@ where
{
type Extra = E;
- fn to_rust_ty_or_opaque(&self, ctx: &BindgenContext, extra: &E) -> RustTy {
+ fn to_rust_ty_or_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &E,
+ ) -> syn::Type {
self.try_to_rust_ty(ctx, extra)
- .unwrap_or_else(|_| RustTy::new_opaque(self.to_opaque(ctx, extra)))
+ .unwrap_or_else(|_| self.to_opaque(ctx, extra))
}
}
@@ -3851,7 +3792,7 @@ where
&self,
ctx: &BindgenContext,
_: &(),
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &())
}
}
@@ -3875,7 +3816,7 @@ impl TryToRustTy for Item {
&self,
ctx: &BindgenContext,
_: &(),
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
self.kind().expect_type().try_to_rust_ty(ctx, self)
}
}
@@ -3892,111 +3833,6 @@ impl TryToOpaque for Type {
}
}
-enum RustTyAnnotation {
- None,
- Reference,
- RValueReference,
- HasUnusedTemplateArgs,
- Opaque,
-}
-
-struct RustTy {
- ts: proc_macro2::TokenStream,
- annotation: RustTyAnnotation,
-}
-
-impl From<proc_macro2::TokenStream> for RustTy {
- fn from(ts: proc_macro2::TokenStream) -> Self {
- RustTy::new(ts)
- }
-}
-
-impl RustTy {
- fn new(ts: proc_macro2::TokenStream) -> Self {
- Self {
- ts,
- annotation: RustTyAnnotation::None,
- }
- }
-
- fn new_opaque(ts: proc_macro2::TokenStream) -> Self {
- Self {
- ts,
- annotation: RustTyAnnotation::Opaque,
- }
- }
-
- fn new_reference(
- ts: proc_macro2::TokenStream,
- inner: RustTyAnnotation,
- ) -> Self {
- let annotation = match inner {
- RustTyAnnotation::HasUnusedTemplateArgs |
- RustTyAnnotation::Opaque => inner,
- _ => RustTyAnnotation::Reference,
- };
- Self { ts, annotation }
- }
-
- fn new_rvalue_reference(
- ts: proc_macro2::TokenStream,
- inner: RustTyAnnotation,
- ) -> Self {
- let annotation = match inner {
- RustTyAnnotation::HasUnusedTemplateArgs |
- RustTyAnnotation::Opaque => inner,
- _ => RustTyAnnotation::RValueReference,
- };
- Self { ts, annotation }
- }
-
- // We're constructing some outer type composed of an inner type,
- // e.g. a reference to a T - the inner type is T
- fn wraps(ts: proc_macro2::TokenStream, inner: RustTyAnnotation) -> Self {
- let annotation = match inner {
- RustTyAnnotation::HasUnusedTemplateArgs => {
- RustTyAnnotation::HasUnusedTemplateArgs
- }
- _ => RustTyAnnotation::None,
- };
- Self { ts, annotation }
- }
-
- fn with_unused_template_args(
- ts: proc_macro2::TokenStream,
- has_unused_args: bool,
- ) -> Self {
- Self {
- ts,
- annotation: if has_unused_args {
- RustTyAnnotation::HasUnusedTemplateArgs
- } else {
- RustTyAnnotation::None
- },
- }
- }
-
- // Where this is called, we're discarding information about whether
- // a type is a reference or a pointer. This is not desirable.
- fn ignore_annotations(self) -> proc_macro2::TokenStream {
- self.ts
- }
-
- // Use when this is an inner type and will become part of an outer type.
- // Pass the annotation into [wraps]
- fn into_outer_type(self) -> (proc_macro2::TokenStream, RustTyAnnotation) {
- (self.ts, self.annotation)
- }
-
- fn into_unannotated_ts(self) -> error::Result<proc_macro2::TokenStream> {
- if matches!(self.annotation, RustTyAnnotation::None) {
- Ok(self.ts)
- } else {
- Err(error::Error::ReferenceButCouldNotRecord)
- }
- }
-}
-
impl TryToRustTy for Type {
type Extra = Item;
@@ -4004,76 +3840,19 @@ impl TryToRustTy for Type {
&self,
ctx: &BindgenContext,
item: &Item,
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
use self::helpers::ast_ty::*;
match *self.kind() {
- TypeKind::Void => Ok(c_void(ctx).into()),
+ TypeKind::Void => Ok(c_void(ctx)),
// TODO: we should do something smart with nullptr, or maybe *const
// c_void is enough?
- TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true).into()),
+ TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)),
TypeKind::Int(ik) => {
- match ik {
- IntKind::Bool => Ok(quote! { bool }.into()),
- IntKind::Char { .. } => Ok(raw_type(ctx, "c_char").into()),
- IntKind::SChar => Ok(raw_type(ctx, "c_schar").into()),
- IntKind::UChar => Ok(raw_type(ctx, "c_uchar").into()),
- IntKind::Short => Ok(raw_type(ctx, "c_short").into()),
- IntKind::UShort => Ok(raw_type(ctx, "c_ushort").into()),
- IntKind::Int => Ok(raw_type(ctx, "c_int").into()),
- IntKind::UInt => Ok(raw_type(ctx, "c_uint").into()),
- IntKind::Long => Ok(raw_type(ctx, "c_long").into()),
- IntKind::ULong => Ok(raw_type(ctx, "c_ulong").into()),
- IntKind::LongLong => Ok(raw_type(ctx, "c_longlong").into()),
- IntKind::ULongLong => {
- Ok(raw_type(ctx, "c_ulonglong").into())
- }
- IntKind::WChar => {
- let layout = self
- .layout(ctx)
- .expect("Couldn't compute wchar_t's layout?");
- let ty = Layout::known_type_for_size(ctx, layout.size)
- .expect("Non-representable wchar_t?");
- let ident = ctx.rust_ident_raw(ty);
- Ok(quote! { #ident }.into())
- }
-
- IntKind::I8 => Ok(quote! { i8 }.into()),
- IntKind::U8 => Ok(quote! { u8 }.into()),
- IntKind::I16 => Ok(quote! { i16 }.into()),
- IntKind::Char16 => Ok(quote! { c_char16_t }.into()),
- IntKind::U16 => Ok(quote! { u16 }.into()),
- IntKind::I32 => Ok(quote! { i32 }.into()),
- IntKind::U32 => Ok(quote! { u32 }.into()),
- IntKind::I64 => Ok(quote! { i64 }.into()),
- IntKind::U64 => Ok(quote! { u64 }.into()),
- IntKind::Custom { name, .. } => {
- Ok(proc_macro2::TokenStream::from_str(name)
- .unwrap()
- .into())
- }
- IntKind::U128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
- quote! { u128 }
- } else {
- // Best effort thing, but wrong alignment
- // unfortunately.
- quote! { [u64; 2] }
- }
- .into())
- }
- IntKind::I128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
- quote! { i128 }
- } else {
- quote! { [u64; 2] }
- }
- .into())
- }
- }
+ Ok(int_kind_rust_type(ctx, ik, self.layout(ctx)))
}
TypeKind::Float(fk) => {
- Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)).into())
+ Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)))
}
TypeKind::Complex(fk) => {
let float_path =
@@ -4081,42 +3860,30 @@ impl TryToRustTy for Type {
ctx.generated_bindgen_complex();
Ok(if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenComplex<#float_path>
- }
+ syn::parse_quote! { root::__BindgenComplex<#float_path> }
} else {
- quote! {
- __BindgenComplex<#float_path>
- }
- }
- .into())
+ syn::parse_quote! { __BindgenComplex<#float_path> }
+ })
}
- TypeKind::Function(ref fs) => {
+ TypeKind::Function(ref signature) => {
// We can't rely on the sizeof(Option<NonZero<_>>) ==
// sizeof(NonZero<_>) optimization with opaque blobs (because
// they aren't NonZero), so don't *ever* use an or_opaque
// variant here.
- let ty = fs.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
+ let ty = signature.try_to_rust_ty(ctx, item)?;
let prefix = ctx.trait_prefix();
- Ok(quote! {
- ::#prefix::option::Option<#ty>
- }
- .into())
+ Ok(syn::parse_quote! { ::#prefix::option::Option<#ty> })
}
TypeKind::Array(item, len) | TypeKind::Vector(item, len) => {
- let ty =
- item.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
- Ok(quote! {
- [ #ty ; #len ]
- }
- .into())
+ let ty = item.try_to_rust_ty(ctx, &())?;
+ Ok(syn::parse_quote! { [ #ty ; #len ] })
}
TypeKind::Enum(..) => {
let path = item.namespace_aware_canonical_path(ctx);
let path = proc_macro2::TokenStream::from_str(&path.join("::"))
.unwrap();
- Ok(quote!(#path).into())
+ Ok(syn::parse_quote!(#path))
}
TypeKind::TemplateInstantiation(ref inst) => {
inst.try_to_rust_ty(ctx, item)
@@ -4127,22 +3894,22 @@ impl TryToRustTy for Type {
TypeKind::BlockPointer(..) => {
if self.is_block_pointer() && !ctx.options().generate_block {
let void = c_void(ctx);
- return Ok(void.to_ptr(/* is_const = */ false).into());
+ return Ok(void.to_ptr(/* is_const = */ false));
}
- let (used_template_params, _) = item.used_template_params(ctx);
- let has_used_template_params = used_template_params
- .into_iter()
- .any(|param| param.is_template_param(ctx, &()));
- if item.is_opaque(ctx, &()) && has_used_template_params {
+ if item.is_opaque(ctx, &()) &&
+ item.used_template_params(ctx)
+ .into_iter()
+ .any(|param| param.is_template_param(ctx, &()))
+ {
self.try_to_opaque(ctx, item)
} else if let Some(ty) = self
.name()
.and_then(|name| utils::type_from_named(ctx, name))
{
- Ok(ty.into())
+ Ok(ty)
} else {
- Ok(utils::build_path(item, ctx)?.into())
+ utils::build_path(item, ctx)
}
}
TypeKind::Comp(ref info) => {
@@ -4153,15 +3920,21 @@ impl TryToRustTy for Type {
return self.try_to_opaque(ctx, item);
}
- Ok(utils::build_path(item, ctx)?.into())
+ utils::build_path(item, ctx)
}
TypeKind::Opaque => self.try_to_opaque(ctx, item),
- TypeKind::Pointer(inner) | TypeKind::Reference(inner, _) => {
+ TypeKind::Pointer(inner) | TypeKind::Reference(inner) => {
+ // Check that this type has the same size as the target's pointer type.
+ let size = self.get_layout(ctx, item).size;
+ if size != ctx.target_pointer_size() {
+ return Err(Error::InvalidPointerSize {
+ ty_name: self.name().unwrap_or("unknown").into(),
+ ty_size: size,
+ ptr_size: ctx.target_pointer_size(),
+ });
+ }
+
let is_const = ctx.resolve_type(inner).is_const();
- let is_reference =
- matches!(self.kind(), TypeKind::Reference(_, false));
- let is_rvalue_reference =
- matches!(self.kind(), TypeKind::Reference(_, true));
let inner =
inner.into_resolver().through_type_refs().resolve(ctx);
@@ -4173,48 +3946,29 @@ impl TryToRustTy for Type {
// Regardless if we can properly represent the inner type, we
// should always generate a proper pointer here, so use
// infallible conversion of the inner type.
- let (mut ty, inner_annotations) =
- inner.to_rust_ty_or_opaque(ctx, &()).into_outer_type();
- ty.append_implicit_template_params(ctx, inner);
+ let ty = inner
+ .to_rust_ty_or_opaque(ctx, &())
+ .with_implicit_template_params(ctx, inner);
// Avoid the first function pointer level, since it's already
// represented in Rust.
if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
{
- Ok(RustTy::wraps(ty, inner_annotations))
+ Ok(ty)
} else {
- let ty_ptr = ty.to_ptr(is_const);
- Ok(if is_rvalue_reference {
- RustTy::new_rvalue_reference(ty_ptr, inner_annotations)
- } else if is_reference {
- RustTy::new_reference(ty_ptr, inner_annotations)
- } else {
- RustTy::wraps(ty_ptr, inner_annotations)
- })
+ Ok(ty.to_ptr(is_const))
}
}
TypeKind::TypeParam => {
let name = item.canonical_name(ctx);
let ident = ctx.rust_ident(name);
- Ok(quote! {
- #ident
- }
- .into())
- }
- TypeKind::ObjCSel => Ok(quote! {
- objc::runtime::Sel
+ Ok(syn::parse_quote! { #ident })
}
- .into()),
- TypeKind::ObjCId => Ok(quote! {
- id
- }
- .into()),
+ TypeKind::ObjCSel => Ok(syn::parse_quote! { objc::runtime::Sel }),
+ TypeKind::ObjCId => Ok(syn::parse_quote! { id }),
TypeKind::ObjCInterface(ref interface) => {
let name = ctx.rust_ident(interface.name());
- Ok(quote! {
- #name
- }
- .into())
+ Ok(syn::parse_quote! { #name })
}
ref u @ TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing {:?}!", u)
@@ -4244,7 +3998,7 @@ impl TryToRustTy for TemplateInstantiation {
&self,
ctx: &BindgenContext,
item: &Item,
- ) -> error::Result<RustTy> {
+ ) -> error::Result<syn::Type> {
if self.is_opaque(ctx, item) {
return Err(error::Error::InstantiationOfOpaqueType);
}
@@ -4288,76 +4042,50 @@ impl TryToRustTy for TemplateInstantiation {
.filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param))
.map(|(arg, _)| {
let arg = arg.into_resolver().through_type_refs().resolve(ctx);
- let mut ty =
- arg.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
- ty.append_implicit_template_params(ctx, arg);
+ let ty = arg
+ .try_to_rust_ty(ctx, &())?
+ .with_implicit_template_params(ctx, arg);
Ok(ty)
})
.collect::<error::Result<Vec<_>>>()?;
- let has_unused_template_args = def_params
- .iter()
- // Only pass type arguments for the type parameters that
- // the def uses.
- .any(|param| !ctx.uses_template_parameter(def.id(), *param));
-
- if template_args.is_empty() {
- return Ok(RustTy::with_unused_template_args(
- ty,
- has_unused_template_args,
- ));
- }
-
- Ok(RustTy::with_unused_template_args(
- quote! {
- #ty < #( #template_args ),* >
- },
- has_unused_template_args,
- ))
+ Ok(if template_args.is_empty() {
+ syn::parse_quote! { #ty }
+ } else {
+ syn::parse_quote! { #ty<#(#template_args),*> }
+ })
}
}
impl TryToRustTy for FunctionSig {
- type Extra = ();
+ type Extra = Item;
fn try_to_rust_ty(
&self,
ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<RustTy> {
+ item: &Item,
+ ) -> error::Result<syn::Type> {
// TODO: we might want to consider ignoring the reference return value.
- let (ret, _) = utils::fnsig_return_ty(ctx, self);
- let (arguments, _) = utils::fnsig_arguments(ctx, self);
+ let ret = utils::fnsig_return_ty(ctx, self);
+ let arguments = utils::fnsig_arguments(ctx, self);
match self.abi(ctx, None) {
- ClangAbi::Known(Abi::ThisCall)
- if !ctx.options().rust_features().thiscall_abi =>
- {
- warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::Vectorcall)
- if !ctx.options().rust_features().vectorcall_abi =>
- {
- warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::CUnwind)
- if !ctx.options().rust_features().c_unwind_abi =>
- {
- warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::EfiApi)
- if !ctx.options().rust_features().abi_efiapi =>
- {
- warn!("Skipping function with efiapi ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new().into())
- }
- abi => Ok(quote! {
- unsafe extern #abi fn ( #( #arguments ),* ) #ret
+ Ok(abi) => Ok(
+ syn::parse_quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret },
+ ),
+ Err(err) => {
+ if matches!(err, error::Error::UnsupportedAbi(_)) {
+ unsupported_abi_diagnostic(
+ self.name(),
+ self.is_variadic(),
+ item.location(),
+ ctx,
+ &err,
+ );
+ }
+
+ Err(err)
}
- .into()),
}
}
}
@@ -4380,25 +4108,36 @@ impl CodeGenerator for Function {
let is_internal = matches!(self.linkage(), Linkage::Internal);
- if is_internal && !ctx.options().wrap_static_fns {
- // We can't do anything with Internal functions if we are not wrapping them so just
- // avoid generating anything for them.
- return None;
- }
+ let signature_item = ctx.resolve_item(self.signature());
+ let signature = signature_item.kind().expect_type().canonical_type(ctx);
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("Signature kind is not a Function: {:?}", signature),
+ };
- let is_pure_virtual = match self.kind() {
- FunctionKind::Method(ref method_kind) => {
- method_kind.is_pure_virtual()
+ if is_internal {
+ if !ctx.options().wrap_static_fns {
+ // We cannot do anything with internal functions if we are not wrapping them so
+ // just avoid generating anything for them.
+ return None;
}
- _ => false,
- };
- let is_virtual = matches!(
- self.kind(),
- FunctionKind::Method(MethodKind::Virtual { .. })
- );
+ if signature.is_variadic() {
+ // We cannot generate wrappers for variadic static functions so we avoid
+ // generating any code for them.
+ variadic_fn_diagnostic(self.name(), item.location(), ctx);
+ return None;
+ }
+ }
+ // Pure virtual methods have no actual symbol, so we can't generate
+ // something meaningful for them.
let is_dynamic_function = match self.kind() {
+ FunctionKind::Method(ref method_kind)
+ if method_kind.is_pure_virtual() =>
+ {
+ return None;
+ }
FunctionKind::Function => {
ctx.options().dynamic_library_name.is_some()
}
@@ -4428,18 +4167,7 @@ impl CodeGenerator for Function {
result.saw_function(seen_symbol_name);
}
- let signature_item = ctx.resolve_item(self.signature());
- let signature = signature_item.kind().expect_type().canonical_type(ctx);
- let signature = match *signature.kind() {
- TypeKind::Function(ref sig) => sig,
- _ => panic!("Signature kind is not a Function: {:?}", signature),
- };
-
- let (args, args_attrs) = utils::fnsig_arguments(ctx, signature);
- let (ret, ret_attr) = utils::fnsig_return_ty(ctx, signature);
-
- let mut attributes = args_attrs;
- attributes.push(ret_attr);
+ let mut attributes = vec![];
if ctx.options().rust_features().must_use_function {
let must_use = signature.must_use() || {
@@ -4460,105 +4188,35 @@ impl CodeGenerator for Function {
attributes.push(attributes::doc(comment));
}
- let mut semantic_annotations =
- CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
-
- if is_pure_virtual {
- semantic_annotations.is_pure_virtual();
- }
-
- if is_virtual {
- semantic_annotations.is_virtual();
- }
-
- semantic_annotations.visibility(self.visibility());
-
let abi = match signature.abi(ctx, Some(name)) {
- ClangAbi::Known(Abi::ThisCall)
- if !ctx.options().rust_features().thiscall_abi =>
- {
- unsupported_abi_diagnostic::<false>(
- name,
- item.location(),
- "thiscall",
- ctx,
- );
- return None;
- }
- ClangAbi::Known(Abi::Vectorcall)
- if !ctx.options().rust_features().vectorcall_abi =>
- {
- unsupported_abi_diagnostic::<false>(
- name,
- item.location(),
- "vectorcall",
- ctx,
- );
- return None;
- }
- ClangAbi::Known(Abi::CUnwind)
- if !ctx.options().rust_features().c_unwind_abi =>
- {
- unsupported_abi_diagnostic::<false>(
- name,
- item.location(),
- "C-unwind",
- ctx,
- );
- return None;
- }
- ClangAbi::Known(Abi::EfiApi)
- if !ctx.options().rust_features().abi_efiapi =>
- {
- unsupported_abi_diagnostic::<true>(
- name,
- item.location(),
- "efiapi",
- ctx,
- );
- return None;
- }
- ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
- unsupported_abi_diagnostic::<true>(
- name,
- item.location(),
- "Win64",
- ctx,
- );
+ Err(err) => {
+ if matches!(err, error::Error::UnsupportedAbi(_)) {
+ unsupported_abi_diagnostic(
+ name,
+ signature.is_variadic(),
+ item.location(),
+ ctx,
+ &err,
+ );
+ }
+
return None;
}
- ClangAbi::Unknown(unknown_abi) => {
+ Ok(ClangAbi::Unknown(unknown_abi)) => {
panic!(
"Invalid or unknown abi {:?} for function {:?} ({:?})",
unknown_abi, canonical_name, self
);
}
- abi => abi,
+ Ok(abi) => abi,
};
- if is_internal && ctx.options().wrap_static_fns {
- result.items_to_serialize.push(item.id());
- }
-
// Handle overloaded functions by giving each overload its own unique
// suffix.
let times_seen = result.overload_number(&canonical_name);
if times_seen > 0 {
write!(&mut canonical_name, "{}", times_seen).unwrap();
}
- if canonical_name != self.name() {
- semantic_annotations.original_name(self.name());
- }
-
- if let Some(special_member_kind) = self.special_member() {
- semantic_annotations.special_member(special_member_kind);
- }
- if self.deleted_fn() {
- semantic_annotations.deleted_fn();
- }
- if self.defaulted_fn() {
- semantic_annotations.defaulted_fn();
- }
let mut has_link_name_attr = false;
if let Some(link_name) = self.link_name() {
@@ -4586,12 +4244,49 @@ impl CodeGenerator for Function {
quote! { #[link(wasm_import_module = #name)] }
});
- if is_internal && ctx.options().wrap_static_fns && !has_link_name_attr {
+ let should_wrap =
+ is_internal && ctx.options().wrap_static_fns && !has_link_name_attr;
+
+ if should_wrap {
let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
attributes.push(attributes::link_name::<true>(&name));
}
- let ident = ctx.rust_ident(canonical_name);
+ let wrap_as_variadic = if should_wrap && !signature.is_variadic() {
+ utils::wrap_as_variadic_fn(ctx, signature, name)
+ } else {
+ None
+ };
+
+ let (ident, args) = if let Some(WrapAsVariadic {
+ idx_of_va_list_arg,
+ new_name,
+ }) = &wrap_as_variadic
+ {
+ (
+ new_name,
+ utils::fnsig_arguments_iter(
+ ctx,
+ // Prune argument at index (idx_of_va_list_arg)
+ signature.argument_types().iter().enumerate().filter_map(
+ |(idx, t)| {
+ if idx == *idx_of_va_list_arg {
+ None
+ } else {
+ Some(t)
+ }
+ },
+ ),
+ // and replace it by a `...` (variadic symbol and the end of the signature)
+ true,
+ ),
+ )
+ } else {
+ (&canonical_name, utils::fnsig_arguments(ctx, signature))
+ };
+ let ret = utils::fnsig_return_ty(ctx, signature);
+
+ let ident = ctx.rust_ident(ident);
let tokens = quote! {
#wasm_link_attribute
extern #abi {
@@ -4600,6 +4295,13 @@ impl CodeGenerator for Function {
}
};
+ // Add the item to the serialization list if necessary
+ if should_wrap {
+ result
+ .items_to_serialize
+ .push((item.id(), wrap_as_variadic));
+ }
+
// If we're doing dynamic binding generation, add to the dynamic items.
if is_dynamic_function {
let args_identifiers =
@@ -4613,7 +4315,7 @@ impl CodeGenerator for Function {
args,
args_identifiers,
ret,
- ret_ty.0,
+ ret_ty,
attributes,
ctx,
);
@@ -4624,17 +4326,73 @@ impl CodeGenerator for Function {
}
}
-fn unsupported_abi_diagnostic<const VARIADIC: bool>(
+#[cfg_attr(not(feature = "experimental"), allow(unused_variables))]
+fn unsupported_abi_diagnostic(
+ fn_name: &str,
+ variadic: bool,
+ location: Option<&crate::clang::SourceLocation>,
+ ctx: &BindgenContext,
+ error: &error::Error,
+) {
+ warn!(
+ "Skipping {}function `{}` because the {}",
+ if variadic { "variadic " } else { "" },
+ fn_name,
+ error
+ );
+
+ #[cfg(feature = "experimental")]
+ if ctx.options().emit_diagnostics {
+ use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
+
+ let mut diag = Diagnostic::default();
+ diag.with_title(
+ format!(
+ "Skipping {}function `{}` because the {}",
+ if variadic { "variadic " } else { "" },
+ fn_name,
+ error
+ ),
+ Level::Warn,
+ )
+ .add_annotation(
+ "No code will be generated for this function.",
+ Level::Warn,
+ )
+ .add_annotation(
+ format!(
+ "The configured Rust version is {}.",
+ ctx.options().rust_target
+ ),
+ Level::Note,
+ );
+
+ if let Some(loc) = location {
+ let (file, line, col, _) = loc.location();
+
+ if let Some(filename) = file.name() {
+ if let Ok(Some(source)) = get_line(&filename, line) {
+ let mut slice = Slice::default();
+ slice
+ .with_source(source)
+ .with_location(filename, line, col);
+ diag.add_slice(slice);
+ }
+ }
+ }
+
+ diag.display()
+ }
+}
+
+fn variadic_fn_diagnostic(
fn_name: &str,
_location: Option<&crate::clang::SourceLocation>,
- abi: &str,
_ctx: &BindgenContext,
) {
warn!(
- "Skipping {}function `{}` with the {} ABI that isn't supported by the configured Rust target",
- if VARIADIC { "variadic " } else { "" },
+ "Cannot generate wrapper for the static variadic function `{}`.",
fn_name,
- abi
);
#[cfg(feature = "experimental")]
@@ -4642,14 +4400,10 @@ fn unsupported_abi_diagnostic<const VARIADIC: bool>(
use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
let mut diag = Diagnostic::default();
- diag
- .with_title(format!(
- "The `{}` {}function uses the {} ABI which is not supported by the configured Rust target.",
- fn_name,
- if VARIADIC { "variadic " } else { "" },
- abi), Level::Warn)
- .add_annotation("No code will be generated for this function.", Level::Warn)
- .add_annotation(format!("The configured Rust version is {}.", String::from(_ctx.options().rust_target)), Level::Note);
+
+ diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn)
+ .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note)
+ .add_annotation("No code will be generated for this function.", Level::Note);
if let Some(loc) = _location {
let (file, line, col, _) = loc.location();
@@ -4686,9 +4440,8 @@ fn objc_method_codegen(
}
let signature = method.signature();
- let (fn_args, _) = utils::fnsig_arguments(ctx, signature);
- let (fn_ret, _) = utils::fnsig_return_ty(ctx, signature);
- // We disregard reference vs pointer attributes for objc methods for now.
+ let fn_args = utils::fnsig_arguments(ctx, signature);
+ let fn_ret = utils::fnsig_return_ty(ctx, signature);
let sig = if method.is_class_method() {
quote! {
@@ -5001,14 +4754,9 @@ pub(crate) fn codegen(
pub(crate) mod utils {
use super::serialize::CSerialize;
- use super::{
- error, CodegenError, CodegenResult, RustTy, RustTyAnnotation,
- ToRustTyOrOpaque,
- };
- use crate::codegen::helpers::{
- CppSemanticAttributeCreator, CppSemanticAttributeSingle,
- };
+ use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
use crate::ir::context::BindgenContext;
+ use crate::ir::context::TypeId;
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
use crate::ir::item::{Item, ItemCanonicalPath};
use crate::ir::ty::TypeKind;
@@ -5071,9 +4819,9 @@ pub(crate) mod utils {
writeln!(code, "// Static wrappers\n")?;
- for &id in &result.items_to_serialize {
- let item = context.resolve_item(id);
- item.serialize(context, (), &mut vec![], &mut code)?;
+ for (id, wrap_as_variadic) in &result.items_to_serialize {
+ let item = context.resolve_item(*id);
+ item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?;
}
std::fs::write(source_path, code)?;
@@ -5081,6 +4829,62 @@ pub(crate) mod utils {
Ok(())
}
+ pub(super) fn wrap_as_variadic_fn(
+ ctx: &BindgenContext,
+ signature: &FunctionSig,
+ name: &str,
+ ) -> Option<super::WrapAsVariadic> {
+ // Fast path, exclude because:
+ // - with 0 args: no va_list possible, so no point searching for one
+ // - with 1 args: cannot have a `va_list` and another arg (required by va_start)
+ if signature.argument_types().len() <= 1 {
+ return None;
+ }
+
+ let mut it = signature.argument_types().iter().enumerate().filter_map(
+ |(idx, (_name, mut type_id))| {
+ // Hand rolled visitor that checks for the presence of `va_list`
+ loop {
+ let ty = ctx.resolve_type(type_id);
+ if Some("__builtin_va_list") == ty.name() {
+ return Some(idx);
+ }
+ match ty.kind() {
+ TypeKind::Alias(type_id_alias) => {
+ type_id = *type_id_alias
+ }
+ TypeKind::ResolvedTypeRef(type_id_typedef) => {
+ type_id = *type_id_typedef
+ }
+ _ => break,
+ }
+ }
+ None
+ },
+ );
+
+ // Return THE idx (by checking that there is no idx after)
+ // This is done since we cannot handle multiple `va_list`
+ it.next().filter(|_| it.next().is_none()).and_then(|idx| {
+ // Call the `wrap_as_variadic_fn` callback
+ #[cfg(feature = "experimental")]
+ {
+ ctx.options()
+ .last_callback(|c| c.wrap_as_variadic_fn(name))
+ .map(|new_name| super::WrapAsVariadic {
+ new_name,
+ idx_of_va_list_arg: idx,
+ })
+ }
+ #[cfg(not(feature = "experimental"))]
+ {
+ let _ = name;
+ let _ = idx;
+ None
+ }
+ })
+ }
+
pub(crate) fn prepend_bitfield_unit_type(
ctx: &BindgenContext,
result: &mut Vec<proc_macro2::TokenStream>,
@@ -5122,7 +4926,7 @@ pub(crate) mod utils {
let items = vec![use_objc, id_type];
let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
+ result.extend(old_items);
}
pub(crate) fn prepend_block_header(
@@ -5141,7 +4945,7 @@ pub(crate) mod utils {
let items = vec![use_block];
let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
+ result.extend(old_items);
}
pub(crate) fn prepend_union_types(
@@ -5200,7 +5004,7 @@ pub(crate) mod utils {
impl<T> ::#prefix::clone::Clone for __BindgenUnionField<T> {
#[inline]
fn clone(&self) -> Self {
- Self::new()
+ *self
}
}
};
@@ -5253,7 +5057,7 @@ pub(crate) mod utils {
];
let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
+ result.extend(old_items);
}
pub(crate) fn prepend_incomplete_array_types(
@@ -5329,7 +5133,7 @@ pub(crate) mod utils {
];
let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
+ result.extend(old_items);
}
pub(crate) fn prepend_complex_type(
@@ -5346,34 +5150,29 @@ pub(crate) mod utils {
let items = vec![complex_type];
let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
+ result.extend(old_items);
}
pub(crate) fn build_path(
item: &Item,
ctx: &BindgenContext,
- ) -> error::Result<proc_macro2::TokenStream> {
+ ) -> error::Result<syn::Type> {
let path = item.namespace_aware_canonical_path(ctx);
let tokens =
proc_macro2::TokenStream::from_str(&path.join("::")).unwrap();
- Ok(tokens)
+ Ok(syn::parse_quote! { #tokens })
}
- fn primitive_ty(
- ctx: &BindgenContext,
- name: &str,
- ) -> proc_macro2::TokenStream {
+ fn primitive_ty(ctx: &BindgenContext, name: &str) -> syn::Type {
let ident = ctx.rust_ident_raw(name);
- quote! {
- #ident
- }
+ syn::parse_quote! { #ident }
}
pub(crate) fn type_from_named(
ctx: &BindgenContext,
name: &str,
- ) -> Option<proc_macro2::TokenStream> {
+ ) -> Option<syn::Type> {
// FIXME: We could use the inner item to check this is really a
// primitive type but, who the heck overrides these anyway?
Some(match name {
@@ -5402,14 +5201,9 @@ pub(crate) mod utils {
fn fnsig_return_ty_internal(
ctx: &BindgenContext,
sig: &FunctionSig,
- include_arrow: bool,
- ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+ ) -> syn::Type {
if sig.is_divergent() {
- return if include_arrow {
- (quote! { -> ! }, quote! {})
- } else {
- (quote! { ! }, quote! {})
- };
+ return syn::parse_quote! { ! };
}
let canonical_type_kind = sig
@@ -5422,101 +5216,80 @@ pub(crate) mod utils {
.expect_type()
.kind();
- if let TypeKind::Void = canonical_type_kind {
- return if include_arrow {
- (quote! {}, quote! {})
- } else {
- (quote! { () }, quote! {})
- };
+ match canonical_type_kind {
+ TypeKind::Void => syn::parse_quote! { () },
+ _ => sig.return_type().to_rust_ty_or_opaque(ctx, &()),
}
-
- let ret_ty = sig.return_type().to_rust_ty_or_opaque(ctx, &());
- let annotations = ret_ty.annotation;
- let ret_ty = ret_ty.ts;
- let ts = if include_arrow {
- quote! { -> #ret_ty }
- } else {
- ret_ty
- };
-
- let mut semantic_annotation =
- CppSemanticAttributeSingle::new(ctx.options());
- match annotations {
- super::RustTyAnnotation::None => {}
- super::RustTyAnnotation::Reference => {
- semantic_annotation.ret_type_reference()
- }
- super::RustTyAnnotation::RValueReference => {
- semantic_annotation.ret_type_rvalue_reference()
- }
- super::RustTyAnnotation::HasUnusedTemplateArgs |
- super::RustTyAnnotation::Opaque => {
- semantic_annotation.incomprehensible_param_in_arg_or_return()
- }
- };
- (ts, semantic_annotation.result())
}
pub(crate) fn fnsig_return_ty(
ctx: &BindgenContext,
sig: &FunctionSig,
- ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
- fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true)
+ ) -> proc_macro2::TokenStream {
+ match fnsig_return_ty_internal(ctx, sig) {
+ syn::Type::Tuple(syn::TypeTuple { elems, .. })
+ if elems.is_empty() =>
+ {
+ quote! {}
+ }
+ ty => quote! { -> #ty },
+ }
}
- pub(crate) fn fnsig_arguments(
+ pub(crate) fn fnsig_argument_type(
ctx: &BindgenContext,
- sig: &FunctionSig,
- ) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) {
+ ty: &TypeId,
+ ) -> syn::Type {
use super::ToPtr;
- let mut unnamed_arguments = 0;
- let mut args: (Vec<_>, Vec<_>) = sig
- .argument_types()
- .iter()
- .map(|&(ref name, ty)| {
- let arg_item = ctx.resolve_item(ty);
- let arg_ty = arg_item.kind().expect_type();
-
- // From the C90 standard[1]:
- //
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- //
- // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
- let arg_details = match *arg_ty.canonical_type(ctx).kind() {
- TypeKind::Array(t, _) => {
- let rust_ty =
- if ctx.options().array_pointers_in_arguments {
- arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
- } else {
- t.to_rust_ty_or_opaque(ctx, &())
- };
- let (inner_ty, annotations) = rust_ty.into_outer_type();
- RustTy::wraps(
- inner_ty.to_ptr(ctx.resolve_type(t).is_const()),
- annotations,
- )
- }
- TypeKind::Pointer(inner) => {
- let inner = ctx.resolve_item(inner);
- let inner_ty = inner.expect_type();
- if let TypeKind::ObjCInterface(ref interface) =
- *inner_ty.canonical_type(ctx).kind()
- {
- let name = ctx.rust_ident(interface.name());
- RustTy::new(quote! {
- #name
- })
- } else {
- arg_item.to_rust_ty_or_opaque(ctx, &())
- }
- }
- _ => arg_item.to_rust_ty_or_opaque(ctx, &()),
+ let arg_item = ctx.resolve_item(ty);
+ let arg_ty = arg_item.kind().expect_type();
+
+ // From the C90 standard[1]:
+ //
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ //
+ // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
+ match *arg_ty.canonical_type(ctx).kind() {
+ TypeKind::Array(t, _) => {
+ let stream = if ctx.options().array_pointers_in_arguments {
+ arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
+ } else {
+ t.to_rust_ty_or_opaque(ctx, &())
};
- let arg_ty = arg_details.ts;
+ stream.to_ptr(ctx.resolve_type(t).is_const())
+ }
+ TypeKind::Pointer(inner) => {
+ let inner = ctx.resolve_item(inner);
+ let inner_ty = inner.expect_type();
+ if let TypeKind::ObjCInterface(ref interface) =
+ *inner_ty.canonical_type(ctx).kind()
+ {
+ let name = ctx.rust_ident(interface.name());
+ syn::parse_quote! { #name }
+ } else {
+ arg_item.to_rust_ty_or_opaque(ctx, &())
+ }
+ }
+ _ => arg_item.to_rust_ty_or_opaque(ctx, &()),
+ }
+ }
+
+ pub(crate) fn fnsig_arguments_iter<
+ 'a,
+ I: Iterator<Item = &'a (Option<String>, crate::ir::context::TypeId)>,
+ >(
+ ctx: &BindgenContext,
+ args_iter: I,
+ is_variadic: bool,
+ ) -> Vec<proc_macro2::TokenStream> {
+ let mut unnamed_arguments = 0;
+ let mut args = args_iter
+ .map(|(name, ty)| {
+ let arg_ty = fnsig_argument_type(ctx, ty);
let arg_name = match *name {
Some(ref name) => ctx.rust_mangle(name).into_owned(),
@@ -5528,38 +5301,31 @@ pub(crate) mod utils {
assert!(!arg_name.is_empty());
let arg_name = ctx.rust_ident(arg_name);
- let mut semantic_annotation =
- CppSemanticAttributeSingle::new(ctx.options());
- match arg_details.annotation {
- RustTyAnnotation::None => {}
- RustTyAnnotation::Reference => {
- semantic_annotation.arg_type_reference(&arg_name)
- }
- RustTyAnnotation::RValueReference => {
- semantic_annotation.arg_type_rvalue_reference(&arg_name)
- }
- RustTyAnnotation::HasUnusedTemplateArgs |
- RustTyAnnotation::Opaque => semantic_annotation
- .incomprehensible_param_in_arg_or_return(),
- };
- (
- quote! {
- #arg_name : #arg_ty
- },
- semantic_annotation.result(),
- )
+ quote! {
+ #arg_name : #arg_ty
+ }
})
- .unzip();
+ .collect::<Vec<_>>();
- if sig.is_variadic() {
- args.0.push(quote! { ... });
- args.1.push(quote! {});
+ if is_variadic {
+ args.push(quote! { ... })
}
args
}
+ pub(crate) fn fnsig_arguments(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> Vec<proc_macro2::TokenStream> {
+ fnsig_arguments_iter(
+ ctx,
+ sig.argument_types().iter(),
+ sig.is_variadic(),
+ )
+ }
+
pub(crate) fn fnsig_argument_identifiers(
ctx: &BindgenContext,
sig: &FunctionSig,
@@ -5596,13 +5362,10 @@ pub(crate) mod utils {
let args = sig.argument_types().iter().map(|&(_, ty)| {
let arg_item = ctx.resolve_item(ty);
- arg_item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations()
+ arg_item.to_rust_ty_or_opaque(ctx, &())
});
- let ret_ty = fnsig_return_ty_internal(
- ctx, sig, /* include_arrow = */ false,
- )
- .0;
+ let ret_ty = fnsig_return_ty_internal(ctx, sig);
quote! {
*const ::block::Block<(#(#args,)*), #ret_ty>
}
diff --git a/codegen/serialize.rs b/codegen/serialize.rs
index ac62023..02c4680 100644
--- a/codegen/serialize.rs
+++ b/codegen/serialize.rs
@@ -10,7 +10,7 @@ use crate::ir::item::ItemCanonicalName;
use crate::ir::item_kind::ItemKind;
use crate::ir::ty::{FloatKind, Type, TypeKind};
-use super::CodegenError;
+use super::{CodegenError, WrapAsVariadic};
fn get_loc(item: &Item) -> String {
item.location()
@@ -18,7 +18,7 @@ fn get_loc(item: &Item) -> String {
.unwrap_or_else(|| "unknown".to_owned())
}
-pub(crate) trait CSerialize<'a> {
+pub(super) trait CSerialize<'a> {
type Extra;
fn serialize<W: Write>(
@@ -31,18 +31,18 @@ pub(crate) trait CSerialize<'a> {
}
impl<'a> CSerialize<'a> for Item {
- type Extra = ();
+ type Extra = &'a Option<WrapAsVariadic>;
fn serialize<W: Write>(
&self,
ctx: &BindgenContext,
- (): Self::Extra,
+ extra: Self::Extra,
stack: &mut Vec<String>,
writer: &mut W,
) -> Result<(), CodegenError> {
match self.kind() {
ItemKind::Function(func) => {
- func.serialize(ctx, self, stack, writer)
+ func.serialize(ctx, (self, extra), stack, writer)
}
kind => Err(CodegenError::Serialize {
msg: format!("Cannot serialize item kind {:?}", kind),
@@ -53,12 +53,12 @@ impl<'a> CSerialize<'a> for Item {
}
impl<'a> CSerialize<'a> for Function {
- type Extra = &'a Item;
+ type Extra = (&'a Item, &'a Option<WrapAsVariadic>);
fn serialize<W: Write>(
&self,
ctx: &BindgenContext,
- item: Self::Extra,
+ (item, wrap_as_variadic): Self::Extra,
stack: &mut Vec<String>,
writer: &mut W,
) -> Result<(), CodegenError> {
@@ -77,43 +77,122 @@ impl<'a> CSerialize<'a> for Function {
_ => unreachable!(),
};
+ assert!(!signature.is_variadic());
+
let name = self.name();
// Function argoments stored as `(name, type_id)` tuples.
let args = {
let mut count = 0;
+ let idx_to_prune = wrap_as_variadic.as_ref().map(
+ |WrapAsVariadic {
+ idx_of_va_list_arg, ..
+ }| *idx_of_va_list_arg,
+ );
+
signature
.argument_types()
.iter()
.cloned()
- .map(|(opt_name, type_id)| {
- (
- opt_name.unwrap_or_else(|| {
- let name = format!("arg_{}", count);
- count += 1;
- name
- }),
- type_id,
- )
+ .enumerate()
+ .filter_map(|(idx, (opt_name, type_id))| {
+ if Some(idx) == idx_to_prune {
+ None
+ } else {
+ Some((
+ opt_name.unwrap_or_else(|| {
+ let name = format!("arg_{}", count);
+ count += 1;
+ name
+ }),
+ type_id,
+ ))
+ }
})
.collect::<Vec<_>>()
};
// The name used for the wrapper self.
let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix());
+
// The function's return type
- let ret_ty = signature.return_type();
+ let (ret_item, ret_ty) = {
+ let type_id = signature.return_type();
+ let ret_item = ctx.resolve_item(type_id);
+ let ret_ty = ret_item.expect_type();
+
+ // Write `ret_ty`.
+ ret_ty.serialize(ctx, ret_item, stack, writer)?;
+
+ (ret_item, ret_ty)
+ };
+
+ const INDENT: &str = " ";
- // Write `ret_ty wrap_name(args) { return name(arg_names)' }`
- ret_ty.serialize(ctx, (), stack, writer)?;
+ // Write `wrap_name(args`.
write!(writer, " {}(", wrap_name)?;
serialize_args(&args, ctx, writer)?;
- write!(writer, ") {{ return {}(", name)?;
- serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| {
+
+ if wrap_as_variadic.is_none() {
+ // Write `) { name(` if the function returns void and `) { return name(` if it does not.
+ if ret_ty.is_void() {
+ write!(writer, ") {{ {}(", name)?;
+ } else {
+ write!(writer, ") {{ return {}(", name)?;
+ }
+ } else {
+ // Write `, ...) {`
+ writeln!(writer, ", ...) {{")?;
+
+ // Declare the return type `RET_TY ret;` if their is a need to do so
+ if !ret_ty.is_void() {
+ write!(writer, "{INDENT}")?;
+ ret_ty.serialize(ctx, ret_item, stack, writer)?;
+ writeln!(writer, " ret;")?;
+ }
+
+ // Setup va_list
+ writeln!(writer, "{INDENT}va_list ap;\n")?;
+ writeln!(
+ writer,
+ "{INDENT}va_start(ap, {});",
+ args.last().unwrap().0
+ )?;
+
+ write!(writer, "{INDENT}")?;
+ // Write `ret = name(` or `name(` depending if the function returns something
+ if !ret_ty.is_void() {
+ write!(writer, "ret = ")?;
+ }
+ write!(writer, "{}(", name)?;
+ }
+
+ // Get the arguments names and insert at the right place if necessary `ap`
+ let mut args: Vec<_> = args.into_iter().map(|(name, _)| name).collect();
+ if let Some(WrapAsVariadic {
+ idx_of_va_list_arg, ..
+ }) = wrap_as_variadic
+ {
+ args.insert(*idx_of_va_list_arg, "ap".to_owned());
+ }
+
+ // Write `arg_names);`.
+ serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| {
write!(buf, "{}", name).map_err(From::from)
})?;
- writeln!(writer, "); }}")?;
+ #[rustfmt::skip]
+ write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?;
+
+ if wrap_as_variadic.is_some() {
+ // End va_list and return the result if their is one
+ writeln!(writer, "{INDENT}va_end(ap);")?;
+ if !ret_ty.is_void() {
+ writeln!(writer, "{INDENT}return ret;")?;
+ }
+ }
+
+ writeln!(writer, "}}")?;
Ok(())
}
@@ -243,21 +322,26 @@ impl<'a> CSerialize<'a> for Type {
}
write!(writer, ")")?;
- write!(writer, " (")?;
- serialize_sep(
- ", ",
- signature.argument_types().iter(),
- ctx,
- writer,
- |(name, type_id), ctx, buf| {
- let mut stack = vec![];
- if let Some(name) = name {
- stack.push(name.clone());
- }
- type_id.serialize(ctx, (), &mut stack, buf)
- },
- )?;
- write!(writer, ")")?
+ let args = signature.argument_types();
+ if args.is_empty() {
+ write!(writer, " (void)")?;
+ } else {
+ write!(writer, " (")?;
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), ctx, buf| {
+ let mut stack = vec![];
+ if let Some(name) = name {
+ stack.push(name.clone());
+ }
+ type_id.serialize(ctx, (), &mut stack, buf)
+ },
+ )?;
+ write!(writer, ")")?
+ }
}
TypeKind::ResolvedTypeRef(type_id) => {
if self.is_const() {
diff --git a/codegen/struct_layout.rs b/codegen/struct_layout.rs
index cca4a59..5673060 100644
--- a/codegen/struct_layout.rs
+++ b/codegen/struct_layout.rs
@@ -6,6 +6,7 @@ use crate::ir::comp::CompInfo;
use crate::ir::context::BindgenContext;
use crate::ir::layout::Layout;
use crate::ir::ty::{Type, TypeKind};
+use crate::FieldVisibilityKind;
use proc_macro2::{self, Ident, Span};
use std::cmp;
@@ -26,6 +27,7 @@ pub(crate) struct StructLayoutTracker<'a> {
latest_field_layout: Option<Layout>,
max_field_align: usize,
last_field_was_bitfield: bool,
+ visibility: FieldVisibilityKind,
}
/// Returns a size aligned to a given value.
@@ -88,6 +90,7 @@ impl<'a> StructLayoutTracker<'a> {
comp: &'a CompInfo,
ty: &'a Type,
name: &'a str,
+ visibility: FieldVisibilityKind,
) -> Self {
let known_type_layout = ty.layout(ctx);
let is_packed = comp.is_packed(ctx, known_type_layout.as_ref());
@@ -97,6 +100,7 @@ impl<'a> StructLayoutTracker<'a> {
name,
ctx,
comp,
+ visibility,
is_packed,
known_type_layout,
is_rust_union,
@@ -397,8 +401,10 @@ impl<'a> StructLayoutTracker<'a> {
self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ let vis = super::access_specifier(self.visibility);
+
quote! {
- pub #padding_field_name : #ty ,
+ #vis #padding_field_name : #ty ,
}
}
diff --git a/deps.rs b/deps.rs
index 987225b..be31f92 100644
--- a/deps.rs
+++ b/deps.rs
@@ -8,13 +8,54 @@ pub(crate) struct DepfileSpec {
}
impl DepfileSpec {
- pub fn write(&self, deps: &BTreeSet<String>) -> std::io::Result<()> {
- let mut buf = format!("{}:", self.output_module);
+ pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
+ std::fs::write(&self.depfile_path, self.to_string(deps))
+ }
+
+ fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
+ // Transforms a string by escaping spaces and backslashes.
+ let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ ");
+ let mut buf = format!("{}:", escape(&self.output_module));
for file in deps {
- buf = format!("{} {}", buf, file);
+ buf = format!("{} {}", buf, escape(file));
}
+ buf
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn escaping_depfile() {
+ let spec = DepfileSpec {
+ output_module: "Mod Name".to_owned(),
+ depfile_path: PathBuf::new(),
+ };
- std::fs::write(&self.depfile_path, &buf)
+ let deps: BTreeSet<_> = vec![
+ r"/absolute/path".into(),
+ r"C:\win\absolute\path".into(),
+ r"../relative/path".into(),
+ r"..\win\relative\path".into(),
+ r"../path/with spaces/in/it".into(),
+ r"..\win\path\with spaces\in\it".into(),
+ r"path\with/mixed\separators".into(),
+ ]
+ .into_iter()
+ .collect();
+ assert_eq!(
+ spec.to_string(&deps),
+ "Mod\\ Name: \
+ ../path/with\\ spaces/in/it \
+ ../relative/path \
+ ..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \
+ ..\\\\win\\\\relative\\\\path \
+ /absolute/path \
+ C:\\\\win\\\\absolute\\\\path \
+ path\\\\with/mixed\\\\separators"
+ );
}
}
diff --git a/extra_assertions.rs b/extra_assertions.rs
index 0888bf3..fbddad7 100644
--- a/extra_assertions.rs
+++ b/extra_assertions.rs
@@ -1,34 +1,17 @@
//! Macros for defining extra assertions that should only be checked in testing
-//! and/or CI when the `testing_only_extra_assertions` feature is enabled.
+//! and/or CI when the `__testing_only_extra_assertions` feature is enabled.
/// Simple macro that forwards to assert! when using
-/// testing_only_extra_assertions.
-#[macro_export]
+/// __testing_only_extra_assertions.
macro_rules! extra_assert {
( $cond:expr ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
+ if cfg!(feature = "__testing_only_extra_assertions") {
assert!($cond);
}
};
( $cond:expr , $( $arg:tt )+ ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
+ if cfg!(feature = "__testing_only_extra_assertions") {
assert!($cond, $( $arg )* )
}
};
}
-
-/// Simple macro that forwards to assert_eq! when using
-/// testing_only_extra_assertions.
-#[macro_export]
-macro_rules! extra_assert_eq {
- ( $lhs:expr , $rhs:expr ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert_eq!($lhs, $rhs);
- }
- };
- ( $lhs:expr , $rhs:expr , $( $arg:tt )+ ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert!($lhs, $rhs, $( $arg )* );
- }
- };
-}
diff --git a/features.rs b/features.rs
index fe6f415..67c6fb4 100644
--- a/features.rs
+++ b/features.rs
@@ -4,260 +4,227 @@
#![deny(clippy::missing_docs_in_private_items)]
#![allow(deprecated)]
+use std::cmp::Ordering;
use std::io;
use std::str::FromStr;
-/// Define RustTarget struct definition, Default impl, and conversions
-/// between RustTarget and String.
-macro_rules! rust_target_def {
- ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
+/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
+macro_rules! define_rust_targets {
+ (
+ Nightly => {$($nightly_feature:ident $(: #$issue:literal)?),* $(,)?} $(,)?
+ $(
+ $(#[$attrs:meta])*
+ $variant:ident($minor:literal) => {$($feature:ident $(: #$pull:literal)?),* $(,)?},
+ )*
+ $(,)?
+ ) => {
/// Represents the version of the Rust language to target.
///
/// To support a beta release, use the corresponding stable release.
///
/// This enum will have more variants added as necessary.
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash)]
#[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RustTarget {
+ /// Rust Nightly
+ $(#[doc = concat!(
+ "- [`", stringify!($nightly_feature), "`]",
+ "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
+ )])*
+ Nightly,
$(
- $(
- #[$attr]
- )*
- $release,
+ #[doc = concat!("Rust 1.", stringify!($minor))]
+ $(#[doc = concat!(
+ "- [`", stringify!($feature), "`]",
+ "(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")",
+ )])*
+ $(#[$attrs])*
+ $variant,
)*
}
- impl Default for RustTarget {
- /// Gives the latest stable Rust version
- fn default() -> RustTarget {
- LATEST_STABLE_RUST
+ impl RustTarget {
+ fn minor(self) -> Option<u64> {
+ match self {
+ $( Self::$variant => Some($minor),)*
+ Self::Nightly => None
+ }
+ }
+
+ const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] {
+ [$((Self::$variant, $minor),)*]
}
}
- impl FromStr for RustTarget {
- type Err = io::Error;
+ #[cfg(feature = "__cli")]
+ /// Strings of allowed `RustTarget` values
+ pub const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*];
- /// Create a `RustTarget` from a string.
- ///
- /// * The stable/beta versions of Rust are of the form "1.0",
- /// "1.19", etc.
- /// * The nightly version should be specified with "nightly".
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.as_ref() {
- $(
- stringify!($value) => Ok(RustTarget::$release),
- )*
- _ => Err(
- io::Error::new(
- io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid rust target. Accepted values ",
- "are of the form ",
- "\"1.0\" or \"nightly\"."))),
- }
- }
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+ pub(crate) struct RustFeatures {
+ $($(pub(crate) $feature: bool,)*)*
+ $(pub(crate) $nightly_feature: bool,)*
}
- impl From<RustTarget> for String {
+ impl From<RustTarget> for RustFeatures {
fn from(target: RustTarget) -> Self {
- match target {
- $(
- RustTarget::$release => stringify!($value),
- )*
- }.into()
+ if target == RustTarget::Nightly {
+ return Self {
+ $($($feature: true,)*)*
+ $($nightly_feature: true,)*
+ };
+ }
+
+ let mut features = Self {
+ $($($feature: false,)*)*
+ $($nightly_feature: false,)*
+ };
+
+ $(if target >= RustTarget::$variant {
+ $(features.$feature = true;)*
+ })*
+
+ features
}
}
- }
+ };
}
-/// Defines an array slice with all RustTarget values
-macro_rules! rust_target_values_def {
- ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
- /// Strings of allowed `RustTarget` values
- pub static RUST_TARGET_STRINGS: &'static [&str] = &[
- $(
- stringify!($value),
- )*
- ];
+// NOTE: When adding or removing features here, make sure to add the stabilization PR
+// number for the feature if it has been stabilized or the tracking issue number if the feature is
+// not stable.
+define_rust_targets! {
+ Nightly => {
+ thiscall_abi: #42202,
+ vectorcall_abi,
+ },
+ Stable_1_71(71) => { c_unwind_abi: #106075 },
+ Stable_1_68(68) => { abi_efiapi: #105795 },
+ Stable_1_64(64) => { core_ffi_c: #94503 },
+ Stable_1_59(59) => { const_cstr: #54745 },
+ Stable_1_47(47) => { larger_arrays: #74060 },
+ Stable_1_40(40) => { non_exhaustive: #44109 },
+ Stable_1_36(36) => { maybe_uninit: #60445 },
+ Stable_1_33(33) => { repr_packed_n: #57049 },
+ #[deprecated]
+ Stable_1_30(30) => {
+ core_ffi_c_void: #53910,
+ min_const_fn: #54835,
+ },
+ #[deprecated]
+ Stable_1_28(28) => { repr_transparent: #51562 },
+ #[deprecated]
+ Stable_1_27(27) => { must_use_function: #48925 },
+ #[deprecated]
+ Stable_1_26(26) => { i128_and_u128: #49101 },
+ #[deprecated]
+ Stable_1_25(25) => { repr_align: #47006 },
+ #[deprecated]
+ Stable_1_21(21) => { builtin_clone_impls: #43690 },
+ #[deprecated]
+ Stable_1_20(20) => { associated_const: #42809 },
+ #[deprecated]
+ Stable_1_19(19) => { untagged_union: #42068 },
+ #[deprecated]
+ Stable_1_17(17) => { static_lifetime_elision: #39265 },
+ #[deprecated]
+ Stable_1_0(0) => {},
+}
+
+/// Latest stable release of Rust
+pub const LATEST_STABLE_RUST: RustTarget = {
+ // FIXME: replace all this code by
+ // ```
+ // RustTarget::stable_releases()
+ // .into_iter()
+ // .max_by_key(|(_, m)| m)
+ // .map(|(t, _)| t)
+ // .unwrap_or(RustTarget::Nightly)
+ // ```
+ // once those operations can be used in constants.
+ let targets = RustTarget::stable_releases();
+
+ let mut i = 0;
+ let mut latest_target = None;
+ let mut latest_minor = 0;
+
+ while i < targets.len() {
+ let (target, minor) = targets[i];
+
+ if latest_minor < minor {
+ latest_minor = minor;
+ latest_target = Some(target);
+ }
+
+ i += 1;
+ }
+
+ match latest_target {
+ Some(target) => target,
+ None => unreachable!(),
+ }
+};
+
+impl Default for RustTarget {
+ fn default() -> Self {
+ LATEST_STABLE_RUST
}
}
-/// Defines macro which takes a macro
-macro_rules! rust_target_base {
- ( $x_macro:ident ) => {
- $x_macro!(
- /// Rust stable 1.0
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_0 => 1.0;
- /// Rust stable 1.17
- /// * Static lifetime elision ([RFC 1623](https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_17 => 1.17;
- /// Rust stable 1.19
- /// * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_19 => 1.19;
- /// Rust stable 1.20
- /// * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_20 => 1.20;
- /// Rust stable 1.21
- /// * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_21 => 1.21;
- /// Rust stable 1.25
- /// * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_25 => 1.25;
- /// Rust stable 1.26
- /// * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_26 => 1.26;
- /// Rust stable 1.27
- /// * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_27 => 1.27;
- /// Rust stable 1.28
- /// * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562))
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_28 => 1.28;
- /// Rust stable 1.30
- /// * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/)
- /// * [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html)
- #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_30 => 1.30;
- /// Rust stable 1.33
- /// * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049))
- => Stable_1_33 => 1.33;
- /// Rust stable 1.36
- /// * `MaybeUninit` instead of `mem::uninitialized()` ([PR](https://github.com/rust-lang/rust/pull/60445))
- => Stable_1_36 => 1.36;
- /// Rust stable 1.40
- /// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109))
- => Stable_1_40 => 1.40;
- /// Rust stable 1.47
- /// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060))
- => Stable_1_47 => 1.47;
- /// Rust stable 1.64
- /// * `core_ffi_c` ([Tracking issue](https://github.com/rust-lang/rust/issues/94501))
- => Stable_1_64 => 1.64;
- /// Rust stable 1.68
- /// * `abi_efiapi` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/65815))
- => Stable_1_68 => 1.68;
- /// Nightly rust
- /// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
- /// * `vectorcall` calling convention (no tracking issue)
- /// * `c_unwind` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/74990))
- => Nightly => nightly;
- );
+impl PartialOrd for RustTarget {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
}
}
-rust_target_base!(rust_target_def);
-rust_target_base!(rust_target_values_def);
+impl Ord for RustTarget {
+ fn cmp(&self, other: &Self) -> Ordering {
+ match (self.minor(), other.minor()) {
+ (Some(a), Some(b)) => a.cmp(&b),
+ (Some(_), None) => Ordering::Less,
+ (None, Some(_)) => Ordering::Greater,
+ (None, None) => Ordering::Equal,
+ }
+ }
+}
-/// Latest stable release of Rust
-pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68;
+impl FromStr for RustTarget {
+ type Err = io::Error;
-/// Create RustFeatures struct definition, new(), and a getter for each field
-macro_rules! rust_feature_def {
- (
- $( $rust_target:ident {
- $( $( #[$attr:meta] )* => $feature:ident; )*
- } )*
- ) => {
- /// Features supported by a rust target
- #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
- #[allow(missing_docs)] // Documentation should go into the relevant variants.
- pub(crate) struct RustFeatures {
- $( $(
- $(
- #[$attr]
- )*
- pub $feature: bool,
- )* )*
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s == "nightly" {
+ return Ok(Self::Nightly);
}
- impl RustFeatures {
- /// Gives a RustFeatures struct with all features disabled
- fn new() -> Self {
- RustFeatures {
- $( $(
- $feature: false,
- )* )*
+ if let Some(("1", str_minor)) = s.split_once('.') {
+ if let Ok(minor) = str_minor.parse::<u64>() {
+ for (target, target_minor) in Self::stable_releases() {
+ if minor == target_minor {
+ return Ok(target);
+ }
}
}
}
- impl From<RustTarget> for RustFeatures {
- fn from(rust_target: RustTarget) -> Self {
- let mut features = RustFeatures::new();
-
- $(
- if rust_target >= RustTarget::$rust_target {
- $(
- features.$feature = true;
- )*
- }
- )*
-
- features
- }
- }
+ Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "Got an invalid Rust target. Accepted values are of the form \"1.71\" or \"nightly\"."
+ ))
}
}
-// NOTE(emilio): When adding or removing features here, make sure to update the
-// documentation for the relevant variant in the rust_target_base macro
-// definition.
-rust_feature_def!(
- Stable_1_17 {
- => static_lifetime_elision;
- }
- Stable_1_19 {
- => untagged_union;
- }
- Stable_1_20 {
- => associated_const;
- }
- Stable_1_21 {
- => builtin_clone_impls;
- }
- Stable_1_25 {
- => repr_align;
- }
- Stable_1_26 {
- => i128_and_u128;
- }
- Stable_1_27 {
- => must_use_function;
- }
- Stable_1_28 {
- => repr_transparent;
- }
- Stable_1_30 {
- => min_const_fn;
- => core_ffi_c_void;
- }
- Stable_1_33 {
- => repr_packed_n;
- }
- Stable_1_36 {
- => maybe_uninit;
- }
- Stable_1_40 {
- => non_exhaustive;
- }
- Stable_1_47 {
- => larger_arrays;
- }
- Stable_1_64 {
- => core_ffi_c;
- }
- Stable_1_68 {
- => abi_efiapi;
- }
- Nightly {
- => thiscall_abi;
- => vectorcall_abi;
- => c_unwind_abi;
+impl std::fmt::Display for RustTarget {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self.minor() {
+ Some(minor) => write!(f, "1.{}", minor),
+ None => "nightly".fmt(f),
+ }
}
-);
+}
impl Default for RustFeatures {
fn default() -> Self {
- let default_rust_target: RustTarget = Default::default();
- Self::from(default_rust_target)
+ RustTarget::default().into()
}
}
@@ -290,6 +257,12 @@ mod test {
!f_1_21.thiscall_abi &&
!f_1_21.vectorcall_abi
);
+ let features = RustFeatures::from(RustTarget::Stable_1_71);
+ assert!(
+ features.c_unwind_abi &&
+ features.abi_efiapi &&
+ !features.thiscall_abi
+ );
let f_nightly = RustFeatures::from(RustTarget::Nightly);
assert!(
f_nightly.static_lifetime_elision &&
@@ -300,13 +273,12 @@ mod test {
f_nightly.maybe_uninit &&
f_nightly.repr_align &&
f_nightly.thiscall_abi &&
- f_nightly.vectorcall_abi &&
- f_nightly.c_unwind_abi
+ f_nightly.vectorcall_abi
);
}
fn test_target(target_str: &str, target: RustTarget) {
- let target_string: String = target.into();
+ let target_string = target.to_string();
assert_eq!(target_str, target_string);
assert_eq!(target, RustTarget::from_str(target_str).unwrap());
}
@@ -318,6 +290,7 @@ mod test {
test_target("1.19", RustTarget::Stable_1_19);
test_target("1.21", RustTarget::Stable_1_21);
test_target("1.25", RustTarget::Stable_1_25);
+ test_target("1.71", RustTarget::Stable_1_71);
test_target("nightly", RustTarget::Nightly);
}
}
diff --git a/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs
index 12b1fe0..980a551 100644
--- a/ir/analysis/has_vtable.rs
+++ b/ir/analysis/has_vtable.rs
@@ -164,7 +164,7 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::ResolvedTypeRef(t) |
- TypeKind::Reference(t, _) => {
+ TypeKind::Reference(t) => {
trace!(
" aliases and references forward to their inner type"
);
diff --git a/ir/analysis/mod.rs b/ir/analysis/mod.rs
index 0263088..443384a 100644
--- a/ir/analysis/mod.rs
+++ b/ir/analysis/mod.rs
@@ -334,20 +334,13 @@ mod tests {
// Yes, what follows is a **terribly** inefficient set union
// implementation. Don't copy this code outside of this test!
- let original_size = self
- .reachable
- .entry(node)
- .or_insert_with(HashSet::default)
- .len();
+ let original_size = self.reachable.entry(node).or_default().len();
for sub_node in self.graph.0[&node].iter() {
self.reachable.get_mut(&node).unwrap().insert(*sub_node);
- let sub_reachable = self
- .reachable
- .entry(*sub_node)
- .or_insert_with(HashSet::default)
- .clone();
+ let sub_reachable =
+ self.reachable.entry(*sub_node).or_default().clone();
for transitive in sub_reachable {
self.reachable.get_mut(&node).unwrap().insert(transitive);
diff --git a/ir/analysis/template_params.rs b/ir/analysis/template_params.rs
index 3e6cd5e..e4261cf 100644
--- a/ir/analysis/template_params.rs
+++ b/ir/analysis/template_params.rs
@@ -459,7 +459,7 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
}
}
- if cfg!(feature = "testing_only_extra_assertions") {
+ if cfg!(feature = "__testing_only_extra_assertions") {
// Invariant: The `used` map has an entry for every allowlisted
// item, as well as all explicitly blocklisted items that are
// reachable from allowlisted items.
diff --git a/ir/annotations.rs b/ir/annotations.rs
index 423f6c4..d085f5c 100644
--- a/ir/annotations.rs
+++ b/ir/annotations.rs
@@ -9,7 +9,7 @@ use std::str::FromStr;
use crate::clang;
/// What kind of visibility modifer should be used for a struct or field?
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
pub enum FieldVisibilityKind {
/// Fields are marked as private, i.e., struct Foo {bar: bool}
Private,
diff --git a/ir/comp.rs b/ir/comp.rs
index 1ff8961..89e77e1 100644
--- a/ir/comp.rs
+++ b/ir/comp.rs
@@ -4,7 +4,6 @@ use super::analysis::Sizedness;
use super::annotations::Annotations;
use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
use super::dot::DotAttributes;
-use super::function::Visibility;
use super::item::{IsOpaque, Item};
use super::layout::Layout;
use super::template::TemplateParameters;
@@ -73,18 +72,6 @@ impl MethodKind {
}
}
-// The kind of C++ special member.
-// TODO: We don't currently cover copy assignment or move assignment operator
-// because libclang doesn't provide a way to query for them.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum SpecialMemberKind {
- DefaultConstructor,
- CopyConstructor,
- MoveConstructor,
- Destructor,
- AssignmentOperator,
-}
-
/// A struct representing a C++ method, either static, normal, or virtual.
#[derive(Debug)]
pub(crate) struct Method {
@@ -989,10 +976,6 @@ pub(crate) struct CompInfo {
/// Whether this is a struct or a union.
kind: CompKind,
- /// The visibility of this struct or union if it was declared inside of
- /// another type. Top-level types always have public visibility.
- visibility: Visibility,
-
/// The members of this struct or union.
fields: CompFields,
@@ -1072,7 +1055,6 @@ impl CompInfo {
pub(crate) fn new(kind: CompKind) -> Self {
CompInfo {
kind,
- visibility: Visibility::Public,
fields: CompFields::default(),
template_params: vec![],
methods: vec![],
@@ -1184,11 +1166,6 @@ impl CompInfo {
}
}
- /// Returns the visibility of the type.
- pub fn visibility(&self) -> Visibility {
- self.visibility
- }
-
/// Returns whether we have a too large bitfield unit, in which case we may
/// not be able to derive some of the things we should be able to normally
/// derive.
@@ -1278,7 +1255,6 @@ impl CompInfo {
debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
let mut ci = CompInfo::new(kind);
- ci.visibility = Visibility::from(cursor.access_specifier());
ci.is_forward_declaration =
location.map_or(true, |cur| match cur.kind() {
CXCursor_ParmDecl => true,
diff --git a/ir/context.rs b/ir/context.rs
index 80e7f8d..c5e2832 100644
--- a/ir/context.rs
+++ b/ir/context.rs
@@ -356,8 +356,16 @@ pub(crate) struct BindgenContext {
/// This needs to be an std::HashMap because the cexpr API requires it.
parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>,
+ /// A map with all include locations.
+ ///
+ /// This is needed so that items are created in the order they are defined in.
+ ///
+ /// The key is the included file, the value is a pair of the source file and
+ /// the position of the `#include` directive in the source file.
+ includes: StdHashMap<String, (String, usize)>,
+
/// A set of all the included filenames.
- deps: BTreeSet<String>,
+ deps: BTreeSet<Box<str>>,
/// The active replacements collected from replaces="xxx" annotations.
replacements: HashMap<Vec<String>, ItemId>,
@@ -560,6 +568,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
BindgenContext {
items: vec![Some(root_module)],
+ includes: Default::default(),
deps,
types: Default::default(),
type_params: Default::default(),
@@ -634,16 +643,33 @@ If you encounter an error missing from this list, please file an issue or a PR!"
)
}
- /// Add another path to the set of included files.
- pub(crate) fn include_file(&mut self, filename: String) {
- for cb in &self.options().parse_callbacks {
- cb.include_file(&filename);
- }
- self.deps.insert(filename);
+ /// Add the location of the `#include` directive for the `included_file`.
+ pub(crate) fn add_include(
+ &mut self,
+ source_file: String,
+ included_file: String,
+ offset: usize,
+ ) {
+ self.includes
+ .entry(included_file)
+ .or_insert((source_file, offset));
+ }
+
+ /// Get the location of the first `#include` directive for the `included_file`.
+ pub(crate) fn included_file_location(
+ &self,
+ included_file: &str,
+ ) -> Option<(String, usize)> {
+ self.includes.get(included_file).cloned()
+ }
+
+ /// Add an included file.
+ pub(crate) fn add_dep(&mut self, dep: Box<str>) {
+ self.deps.insert(dep);
}
/// Get any included files.
- pub(crate) fn deps(&self) -> &BTreeSet<String> {
+ pub(crate) fn deps(&self) -> &BTreeSet<Box<str>> {
&self.deps
}
@@ -1193,11 +1219,11 @@ If you encounter an error missing from this list, please file an issue or a PR!"
Ok((ret, self.options))
}
- /// When the `testing_only_extra_assertions` feature is enabled, this
+ /// When the `__testing_only_extra_assertions` feature is enabled, this
/// function walks the IR graph and asserts that we do not have any edges
/// referencing an ItemId for which we do not have an associated IR item.
fn assert_no_dangling_references(&self) {
- if cfg!(feature = "testing_only_extra_assertions") {
+ if cfg!(feature = "__testing_only_extra_assertions") {
for _ in self.assert_no_dangling_item_traversal() {
// The iterator's next method does the asserting for us.
}
@@ -1218,11 +1244,11 @@ If you encounter an error missing from this list, please file an issue or a PR!"
)
}
- /// When the `testing_only_extra_assertions` feature is enabled, walk over
+ /// When the `__testing_only_extra_assertions` feature is enabled, walk over
/// every item and ensure that it is in the children set of one of its
/// module ancestors.
fn assert_every_item_in_a_module(&self) {
- if cfg!(feature = "testing_only_extra_assertions") {
+ if cfg!(feature = "__testing_only_extra_assertions") {
assert!(self.in_codegen_phase());
assert!(self.current_module == self.root_module);
@@ -1971,9 +1997,6 @@ If you encounter an error missing from this list, please file an issue or a PR!"
CXType_Short => TypeKind::Int(IntKind::Short),
CXType_UShort => TypeKind::Int(IntKind::UShort),
CXType_WChar => TypeKind::Int(IntKind::WChar),
- CXType_Char16 if self.options().use_distinct_char16_t => {
- TypeKind::Int(IntKind::Char16)
- }
CXType_Char16 => TypeKind::Int(IntKind::U16),
CXType_Char32 => TypeKind::Int(IntKind::U32),
CXType_Long => TypeKind::Int(IntKind::Long),
@@ -2320,7 +2343,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
if self.options().allowlisted_types.is_empty() &&
self.options().allowlisted_functions.is_empty() &&
self.options().allowlisted_vars.is_empty() &&
- self.options().allowlisted_files.is_empty()
+ self.options().allowlisted_files.is_empty() &&
+ self.options().allowlisted_items.is_empty()
{
return true;
}
@@ -2350,6 +2374,11 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let name = item.path_for_allowlisting(self)[1..].join("::");
debug!("allowlisted_items: testing {:?}", name);
+
+ if self.options().allowlisted_items.matches(&name) {
+ return true;
+ }
+
match *item.kind() {
ItemKind::Module(..) => true,
ItemKind::Function(_) => {
@@ -2473,6 +2502,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
for item in self.options().allowlisted_types.unmatched_items() {
unused_regex_diagnostic(item, "--allowlist-type", self);
}
+
+ for item in self.options().allowlisted_items.unmatched_items() {
+ unused_regex_diagnostic(item, "--allowlist-items", self);
+ }
}
/// Convenient method for getting the prefix to use for most traits in
diff --git a/ir/enum_ty.rs b/ir/enum_ty.rs
index a863340..70cf0ea 100644
--- a/ir/enum_ty.rs
+++ b/ir/enum_ty.rs
@@ -2,7 +2,6 @@
use super::super::codegen::EnumVariation;
use super::context::{BindgenContext, TypeId};
-use super::function::Visibility;
use super::item::Item;
use super::ty::{Type, TypeKind};
use crate::clang;
@@ -33,10 +32,6 @@ pub(crate) struct Enum {
/// The different variants, with explicit values.
variants: Vec<EnumVariant>,
-
- /// The visibility of this enum if it was declared inside of
- /// another type. Top-level types always have public visibility.
- pub(crate) visibility: Visibility,
}
impl Enum {
@@ -44,13 +39,8 @@ impl Enum {
pub(crate) fn new(
repr: Option<TypeId>,
variants: Vec<EnumVariant>,
- visibility: Visibility,
) -> Self {
- Enum {
- repr,
- variants,
- visibility,
- }
+ Enum { repr, variants }
}
/// Get this enumeration's representation.
@@ -66,7 +56,6 @@ impl Enum {
/// Construct an enumeration from the given Clang type.
pub(crate) fn from_ty(
ty: &clang::Type,
- visibility: Visibility,
ctx: &mut BindgenContext,
) -> Result<Self, ParseError> {
use clang_sys::*;
@@ -158,7 +147,7 @@ impl Enum {
}
CXChildVisit_Continue
});
- Ok(Enum::new(repr, variants, visibility))
+ Ok(Enum::new(repr, variants))
}
fn is_matching_enum(
diff --git a/ir/function.rs b/ir/function.rs
index d38c60e..5bfb70e 100644
--- a/ir/function.rs
+++ b/ir/function.rs
@@ -1,6 +1,6 @@
//! Intermediate representation for C/C++ functions and methods.
-use super::comp::{MethodKind, SpecialMemberKind};
+use super::comp::MethodKind;
use super::context::{BindgenContext, TypeId};
use super::dot::DotAttributes;
use super::item::Item;
@@ -9,9 +9,7 @@ use super::ty::TypeKind;
use crate::callbacks::{ItemInfo, ItemKind};
use crate::clang::{self, Attribute};
use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
-use clang_sys::{
- self, CXCallingConv, CX_CXXAccessSpecifier, CX_CXXPrivate, CX_CXXProtected,
-};
+use clang_sys::{self, CXCallingConv};
use quote::TokenStreamExt;
use std::io;
@@ -72,75 +70,6 @@ pub(crate) enum Linkage {
Internal,
}
-/// Visibility
-#[derive(Debug, Clone, Copy)]
-pub enum Visibility {
- Public,
- Protected,
- Private,
-}
-
-impl From<CX_CXXAccessSpecifier> for Visibility {
- fn from(access_specifier: CX_CXXAccessSpecifier) -> Self {
- if access_specifier == CX_CXXPrivate {
- Visibility::Private
- } else if access_specifier == CX_CXXProtected {
- Visibility::Protected
- } else {
- Visibility::Public
- }
- }
-}
-
-/// Autocxx specialized function information
-#[derive(Debug)]
-pub(crate) struct AutocxxFuncInfo {
- /// C++ Special member kind, if applicable
- special_member: Option<SpecialMemberKind>,
- /// Whether it is private
- visibility: Visibility,
- /// =delete
- is_deleted: bool,
- /// =default
- is_defaulted: bool,
-}
-
-impl AutocxxFuncInfo {
- fn new(
- special_member: Option<SpecialMemberKind>,
- visibility: Visibility,
- is_deleted: bool,
- is_defaulted: bool,
- ) -> Self {
- Self {
- special_member,
- visibility,
- is_deleted,
- is_defaulted,
- }
- }
-
- /// Get this function's C++ special member kind.
- pub fn special_member(&self) -> Option<SpecialMemberKind> {
- self.special_member
- }
-
- /// Whether it is private
- pub fn visibility(&self) -> Visibility {
- self.visibility
- }
-
- /// Whether this is a function that's been deleted (=delete)
- pub fn deleted_fn(&self) -> bool {
- self.is_deleted
- }
-
- /// Whether this is a function that's been deleted (=default)
- pub fn defaulted_fn(&self) -> bool {
- self.is_defaulted
- }
-}
-
/// A function declaration, with a signature, arguments, and argument names.
///
/// The argument names vector must be the same length as the ones in the
@@ -164,9 +93,6 @@ pub(crate) struct Function {
/// The linkage of the function.
linkage: Linkage,
-
- /// Autocxx extension information
- autocxx: AutocxxFuncInfo,
}
impl Function {
@@ -178,7 +104,6 @@ impl Function {
signature: TypeId,
kind: FunctionKind,
linkage: Linkage,
- autocxx: AutocxxFuncInfo,
) -> Self {
Function {
name,
@@ -187,7 +112,6 @@ impl Function {
signature,
kind,
linkage,
- autocxx,
}
}
@@ -220,26 +144,6 @@ impl Function {
pub(crate) fn linkage(&self) -> Linkage {
self.linkage
}
-
- /// Get this function's C++ special member kind.
- pub fn special_member(&self) -> Option<SpecialMemberKind> {
- self.autocxx.special_member()
- }
-
- /// Whether it is private
- pub fn visibility(&self) -> Visibility {
- self.autocxx.visibility()
- }
-
- /// Whether this is a function that's been deleted (=delete)
- pub fn deleted_fn(&self) -> bool {
- self.autocxx.deleted_fn()
- }
-
- /// Whether this is a function that's been deleted (=default)
- pub fn defaulted_fn(&self) -> bool {
- self.autocxx.defaulted_fn()
- }
}
impl DotAttributes for Function {
@@ -286,6 +190,8 @@ pub enum Abi {
Win64,
/// The "C-unwind" ABI.
CUnwind,
+ /// The "system" ABI.
+ System,
}
impl FromStr for Abi {
@@ -302,6 +208,7 @@ impl FromStr for Abi {
"aapcs" => Ok(Self::Aapcs),
"win64" => Ok(Self::Win64),
"C-unwind" => Ok(Self::CUnwind),
+ "system" => Ok(Self::System),
_ => Err(format!("Invalid or unknown ABI {:?}", s)),
}
}
@@ -319,6 +226,7 @@ impl std::fmt::Display for Abi {
Self::Aapcs => "aapcs",
Self::Win64 => "win64",
Self::CUnwind => "C-unwind",
+ Abi::System => "system",
};
s.fmt(f)
@@ -501,6 +409,11 @@ fn args_from_ty_and_cursor(
}
impl FunctionSig {
+ /// Get the function name.
+ pub(crate) fn name(&self) -> &str {
+ &self.name
+ }
+
/// Construct a new function signature from the given Clang type.
pub(crate) fn from_ty(
ty: &clang::Type,
@@ -518,6 +431,15 @@ impl FunctionSig {
let spelling = cursor.spelling();
+ // Don't parse operatorxx functions in C++
+ let is_operator = |spelling: &str| {
+ spelling.starts_with("operator") &&
+ !clang::is_valid_identifier(spelling)
+ };
+ if is_operator(&spelling) {
+ return Err(ParseError::Continue);
+ }
+
// Constructors of non-type template parameter classes for some reason
// include the template parameter in their name. Just skip them, since
// we don't handle well non-type template parameters anyway.
@@ -600,10 +522,7 @@ impl FunctionSig {
let is_const = is_method && cursor.method_is_const();
let is_virtual = is_method && cursor.method_is_virtual();
let is_static = is_method && cursor.method_is_static();
- if !is_static &&
- (!is_virtual ||
- ctx.options().use_specific_virtual_function_receiver)
- {
+ if !is_static && !is_virtual {
let parent = cursor.semantic_parent();
let class = Item::parse(parent, None, ctx)
.expect("Expected to parse the class");
@@ -627,7 +546,7 @@ impl FunctionSig {
Item::builtin_type(TypeKind::Pointer(class), false, ctx);
args.insert(0, (Some("this".into()), ptr));
} else if is_virtual {
- let void = Item::builtin_type(TypeKind::Void, is_const, ctx);
+ let void = Item::builtin_type(TypeKind::Void, false, ctx);
let ptr =
Item::builtin_type(TypeKind::Pointer(void), false, ctx);
args.insert(0, (Some("this".into()), ptr));
@@ -695,10 +614,10 @@ impl FunctionSig {
&self,
ctx: &BindgenContext,
name: Option<&str>,
- ) -> ClangAbi {
+ ) -> crate::codegen::error::Result<ClangAbi> {
// FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx`
// instead?.
- if let Some(name) = name {
+ let abi = if let Some(name) = name {
if let Some((abi, _)) = ctx
.options()
.abi_overrides
@@ -718,6 +637,33 @@ impl FunctionSig {
ClangAbi::Known(*abi)
} else {
self.abi
+ };
+
+ match abi {
+ ClangAbi::Known(Abi::ThisCall)
+ if !ctx.options().rust_features().thiscall_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("thiscall"))
+ }
+ ClangAbi::Known(Abi::Vectorcall)
+ if !ctx.options().rust_features().vectorcall_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall"))
+ }
+ ClangAbi::Known(Abi::CUnwind)
+ if !ctx.options().rust_features().c_unwind_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind"))
+ }
+ ClangAbi::Known(Abi::EfiApi)
+ if !ctx.options().rust_features().abi_efiapi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("efiapi"))
+ }
+ ClangAbi::Known(Abi::Win64) if self.is_variadic() => {
+ Err(crate::codegen::error::Error::UnsupportedAbi("Win64"))
+ }
+ abi => Ok(abi),
}
}
@@ -775,7 +721,9 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}
- let visibility = Visibility::from(cursor.access_specifier());
+ if cursor.access_specifier() == CX_CXXPrivate {
+ return Err(ParseError::Continue);
+ }
let linkage = cursor.linkage();
let linkage = match linkage {
@@ -795,6 +743,10 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}
+ if cursor.is_deleted_function() {
+ return Err(ParseError::Continue);
+ }
+
// We cannot handle `inline` functions that are not `static`.
if context.options().wrap_static_fns &&
cursor.is_inlined_function() &&
@@ -833,23 +785,7 @@ impl ClangSubItemParser for Function {
}
assert!(!name.is_empty(), "Empty function name.");
- let operator_suffix = name.strip_prefix("operator");
- let special_member = if let Some(operator_suffix) = operator_suffix {
- // We can't represent operatorxx functions as-is because
- // they are not valid identifiers
- if context.options().represent_cxx_operators {
- let (new_suffix, special_member) = match operator_suffix {
- "=" => ("equals", SpecialMemberKind::AssignmentOperator),
- _ => return Err(ParseError::Continue),
- };
- name = format!("operator_{}", new_suffix);
- Some(special_member)
- } else {
- return Err(ParseError::Continue);
- }
- } else {
- None
- };
+ let mangled_name = cursor_mangling(context, &cursor);
let link_name = context.options().last_callback(|callbacks| {
callbacks.generated_link_name_override(ItemInfo {
@@ -858,36 +794,13 @@ impl ClangSubItemParser for Function {
})
});
- let mangled_name = cursor_mangling(context, &cursor);
-
- let special_member = special_member.or_else(|| {
- if cursor.is_default_constructor() {
- Some(SpecialMemberKind::DefaultConstructor)
- } else if cursor.is_copy_constructor() {
- Some(SpecialMemberKind::CopyConstructor)
- } else if cursor.is_move_constructor() {
- Some(SpecialMemberKind::MoveConstructor)
- } else if cursor.kind() == clang_sys::CXCursor_Destructor {
- Some(SpecialMemberKind::Destructor)
- } else {
- None
- }
- });
-
- let autocxx_info = AutocxxFuncInfo::new(
- special_member,
- visibility,
- cursor.is_deleted_function(),
- cursor.is_defaulted_function(),
- );
let function = Self::new(
- name,
+ name.clone(),
mangled_name,
link_name,
sig,
kind,
linkage,
- autocxx_info,
);
Ok(ParseResult::New(function, Some(cursor)))
diff --git a/ir/int.rs b/ir/int.rs
index ea2456e..4251b37 100644
--- a/ir/int.rs
+++ b/ir/int.rs
@@ -54,11 +54,8 @@ pub enum IntKind {
/// A 16-bit signed integer.
I16,
- /// A 16-bit integer, used only for enum size representation.
- U16,
-
/// Either a `char16_t` or a `wchar_t`.
- Char16,
+ U16,
/// A 32-bit signed integer.
I32,
@@ -97,7 +94,7 @@ impl IntKind {
// to know whether it is or not right now (unlike char, there's no
// WChar_S / WChar_U).
Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
- Char16 | WChar | U32 | U64 | U128 => false,
+ WChar | U32 | U64 | U128 => false,
SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
I128 => true,
@@ -115,7 +112,7 @@ impl IntKind {
use self::IntKind::*;
Some(match *self {
Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
- U16 | I16 | Char16 => 2,
+ U16 | I16 => 2,
U32 | I32 => 4,
U64 | I64 => 8,
I128 | U128 => 16,
diff --git a/ir/item.rs b/ir/item.rs
index c35b2ac..0556452 100644
--- a/ir/item.rs
+++ b/ir/item.rs
@@ -98,13 +98,13 @@ pub(crate) trait ItemAncestors {
fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>;
}
-#[cfg(testing_only_extra_assertions)]
+#[cfg(feature = "__testing_only_extra_assertions")]
type DebugOnlyItemSet = ItemSet;
-#[cfg(not(testing_only_extra_assertions))]
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
struct DebugOnlyItemSet;
-#[cfg(not(testing_only_extra_assertions))]
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
impl DebugOnlyItemSet {
fn new() -> Self {
DebugOnlyItemSet
@@ -823,38 +823,6 @@ impl Item {
}
}
- /// Get this item's original C++ name, including any containing types, but without
- /// the namespace name. For nested types, the C++ name differs from the Rust name, e.g.
- /// a nested C++ type `A::B` would correspond to the Rust type `A_B`.
- /// If the item or any of its containing types is anonymous, returns None.
- pub fn original_name(&self, ctx: &BindgenContext) -> Option<String> {
- let target = ctx.resolve_item(self.name_target(ctx));
-
- // Get item and all ancestors until the first enclosing namespace.
- let ancestors: Vec<_> = target
- .ancestors(ctx)
- .map(|id| ctx.resolve_item(id))
- .take_while(|item| !item.is_module())
- .collect();
-
- if ancestors.iter().any(|item| item.is_anon()) {
- return None;
- }
-
- let mut names: Vec<_> = ancestors
- .iter()
- .map(|item| {
- let target = ctx.resolve_item(item.name_target(ctx));
- target.base_name(ctx)
- })
- .filter(|name| !name.is_empty())
- .collect();
-
- names.reverse();
-
- Some(names.join("::"))
- }
-
/// Get the canonical name without taking into account the replaces
/// annotation.
///
@@ -1492,8 +1460,12 @@ impl Item {
cursor
);
}
- Some(filename) => {
- ctx.include_file(filename);
+ Some(included_file) => {
+ for cb in &ctx.options().parse_callbacks {
+ cb.include_file(&included_file);
+ }
+
+ ctx.add_dep(included_file.into_boxed_str());
}
}
}
diff --git a/ir/layout.rs b/ir/layout.rs
index 17ca66e..85a553d 100644
--- a/ir/layout.rs
+++ b/ir/layout.rs
@@ -8,13 +8,13 @@ use std::cmp;
/// A type that represents the struct layout of a type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Layout {
+pub(crate) struct Layout {
/// The size (in bytes) of this layout.
- pub size: usize,
+ pub(crate) size: usize,
/// The alignment (in bytes) of this layout.
- pub align: usize,
+ pub(crate) align: usize,
/// Whether this layout's members are packed or not.
- pub packed: bool,
+ pub(crate) packed: bool,
}
#[test]
@@ -37,13 +37,15 @@ impl Layout {
pub(crate) fn known_type_for_size(
ctx: &BindgenContext,
size: usize,
- ) -> Option<&'static str> {
+ ) -> Option<syn::Type> {
Some(match size {
- 16 if ctx.options().rust_features.i128_and_u128 => "u128",
- 8 => "u64",
- 4 => "u32",
- 2 => "u16",
- 1 => "u8",
+ 16 if ctx.options().rust_features.i128_and_u128 => {
+ syn::parse_quote! { u128 }
+ }
+ 8 => syn::parse_quote! { u64 },
+ 4 => syn::parse_quote! { u32 },
+ 2 => syn::parse_quote! { u16 },
+ 1 => syn::parse_quote! { u8 },
_ => return None,
})
}
@@ -103,7 +105,7 @@ impl Opaque {
pub(crate) fn known_rust_type_for_array(
&self,
ctx: &BindgenContext,
- ) -> Option<&'static str> {
+ ) -> Option<syn::Type> {
Layout::known_type_for_size(ctx, self.0.align)
}
diff --git a/ir/module.rs b/ir/module.rs
index f25ef40..5ec55e9 100644
--- a/ir/module.rs
+++ b/ir/module.rs
@@ -6,6 +6,7 @@ use super::item::ItemSet;
use crate::clang;
use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
use crate::parse_one;
+
use std::io;
/// Whether this module is inline or not.
@@ -82,8 +83,8 @@ impl ClangSubItemParser for Module {
CXCursor_Namespace => {
let module_id = ctx.module(cursor);
ctx.with_module(module_id, |ctx| {
- cursor.visit(|cursor| {
- parse_one(ctx, cursor, Some(module_id.into()))
+ cursor.visit_sorted(ctx, |ctx, child| {
+ parse_one(ctx, child, Some(module_id.into()))
})
});
diff --git a/ir/objc.rs b/ir/objc.rs
index eaf3b8a..93d8b3b 100644
--- a/ir/objc.rs
+++ b/ir/objc.rs
@@ -253,19 +253,38 @@ impl ObjCMethod {
let split_name: Vec<Option<Ident>> = self
.name
.split(':')
- .map(|name| {
+ .enumerate()
+ .map(|(idx, name)| {
if name.is_empty() {
None
+ } else if idx == 0 {
+ // Try to parse the method name as an identifier. Having a keyword is ok
+ // unless it is `crate`, `self`, `super` or `Self`, so we try to add the `_`
+ // suffix to it and parse it.
+ if ["crate", "self", "super", "Self"].contains(&name) {
+ Some(Ident::new(
+ &format!("{}_", name),
+ Span::call_site(),
+ ))
+ } else {
+ Some(Ident::new(name, Span::call_site()))
+ }
} else {
- // Try to parse the current name as an identifier. This might fail if the
- // name is a keyword so we try to prepend "r#" to it and parse again. If
- // this also fails, we panic with the first error.
+ // Try to parse the current joining name as an identifier. This might fail if the name
+ // is a keyword, so we try to "r#" to it and parse again, this could also fail
+ // if the name is `crate`, `self`, `super` or `Self`, so we try to add the `_`
+ // suffix to it and parse again. If this also fails, we panic with the first
+ // error.
Some(
syn::parse_str::<Ident>(name)
.or_else(|err| {
syn::parse_str::<Ident>(&format!("r#{}", name))
.map_err(|_| err)
})
+ .or_else(|err| {
+ syn::parse_str::<Ident>(&format!("{}_", name))
+ .map_err(|_| err)
+ })
.expect("Invalid identifier"),
)
}
diff --git a/ir/template.rs b/ir/template.rs
index a1f8f5f..4dd8442 100644
--- a/ir/template.rs
+++ b/ir/template.rs
@@ -31,7 +31,6 @@ use super::context::{BindgenContext, ItemId, TypeId};
use super::item::{IsOpaque, Item, ItemAncestors};
use super::traversal::{EdgeKind, Trace, Tracer};
use crate::clang;
-use itertools::{Either, Itertools};
/// Template declaration (and such declaration's template parameters) related
/// methods.
@@ -144,9 +143,8 @@ pub(crate) trait TemplateParameters: Sized {
/// Get only the set of template parameters that this item uses. This is a
/// subset of `all_template_params` and does not necessarily contain any of
- /// `self_template_params`. If any are unused, true will be returned
- /// in the second tuple element
- fn used_template_params(&self, ctx: &BindgenContext) -> (Vec<TypeId>, bool)
+ /// `self_template_params`.
+ fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
where
Self: AsRef<ItemId>,
{
@@ -156,18 +154,11 @@ pub(crate) trait TemplateParameters: Sized {
);
let id = *self.as_ref();
- let (used, unused): (Vec<_>, Vec<_>) = ctx
- .resolve_item(id)
+ ctx.resolve_item(id)
.all_template_params(ctx)
.into_iter()
- .partition_map(|p| {
- if ctx.uses_template_parameter(id, p) {
- Either::Left(p)
- } else {
- Either::Right(true)
- }
- });
- (used, !unused.is_empty())
+ .filter(|p| ctx.uses_template_parameter(id, *p))
+ .collect()
}
}
diff --git a/ir/ty.rs b/ir/ty.rs
index 5bf3841..1aee065 100644
--- a/ir/ty.rs
+++ b/ir/ty.rs
@@ -5,7 +5,6 @@ use super::context::{BindgenContext, ItemId, TypeId};
use super::dot::DotAttributes;
use super::enum_ty::Enum;
use super::function::FunctionSig;
-use super::int::IntKind;
use super::item::{IsOpaque, Item};
use super::layout::{Layout, Opaque};
use super::objc::ObjCInterface;
@@ -14,11 +13,12 @@ use super::template::{
};
use super::traversal::{EdgeKind, Trace, Tracer};
use crate::clang::{self, Cursor};
-use crate::ir::function::Visibility;
use crate::parse::{ParseError, ParseResult};
use std::borrow::Cow;
use std::io;
+pub use super::int::IntKind;
+
/// The base representation of a type in bindgen.
///
/// A type has an optional name, which if present cannot be empty, a `layout`
@@ -125,6 +125,10 @@ impl Type {
matches!(self.kind, TypeKind::Enum(..))
}
+ /// Is this void?
+ pub(crate) fn is_void(&self) -> bool {
+ matches!(self.kind, TypeKind::Void)
+ }
/// Is this either a builtin or named type?
pub(crate) fn is_builtin_or_type_param(&self) -> bool {
matches!(
@@ -206,9 +210,10 @@ impl Type {
self.layout.or_else(|| {
match self.kind {
TypeKind::Comp(ref ci) => ci.layout(ctx),
- TypeKind::Array(inner, length) if length == 0 => Some(
- Layout::new(0, ctx.resolve_type(inner).layout(ctx)?.align),
- ),
+ TypeKind::Array(inner, 0) => Some(Layout::new(
+ 0,
+ ctx.resolve_type(inner).layout(ctx)?.align,
+ )),
// FIXME(emilio): This is a hack for anonymous union templates.
// Use the actual pointer size!
TypeKind::Pointer(..) => Some(Layout::new(
@@ -254,9 +259,7 @@ impl Type {
) -> Option<Cow<'a, str>> {
let name_info = match *self.kind() {
TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))),
- TypeKind::Reference(inner, _) => {
- Some((inner, Cow::Borrowed("ref")))
- }
+ TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))),
TypeKind::Array(inner, length) => {
Some((inner, format!("array{}", length).into()))
}
@@ -541,7 +544,7 @@ impl TemplateParameters for TypeKind {
TypeKind::Enum(_) |
TypeKind::Pointer(_) |
TypeKind::BlockPointer(_) |
- TypeKind::Reference(..) |
+ TypeKind::Reference(_) |
TypeKind::UnresolvedTypeRef(..) |
TypeKind::TypeParam |
TypeKind::Alias(_) |
@@ -619,8 +622,7 @@ pub(crate) enum TypeKind {
BlockPointer(TypeId),
/// A reference to a type, as in: int& foo().
- /// The bool represents whether it's rvalue.
- Reference(TypeId, bool),
+ Reference(TypeId),
/// An instantiation of an abstract template definition with a set of
/// concrete template arguments.
@@ -1048,23 +1050,14 @@ impl Type {
}
// XXX: RValueReference is most likely wrong, but I don't think we
// can even add bindings for that, so huh.
- CXType_LValueReference => {
- let inner = Item::from_ty_or_ref(
- ty.pointee_type().unwrap(),
- location,
- None,
- ctx,
- );
- TypeKind::Reference(inner, false)
- }
- CXType_RValueReference => {
+ CXType_RValueReference | CXType_LValueReference => {
let inner = Item::from_ty_or_ref(
ty.pointee_type().unwrap(),
location,
None,
ctx,
);
- TypeKind::Reference(inner, true)
+ TypeKind::Reference(inner)
}
// XXX DependentSizedArray is wrong
CXType_VariableArray | CXType_DependentSizedArray => {
@@ -1122,10 +1115,7 @@ impl Type {
}
}
CXType_Enum => {
- let visibility =
- Visibility::from(cursor.access_specifier());
- let enum_ = Enum::from_ty(ty, visibility, ctx)
- .expect("Not an enum?");
+ let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
if !is_anonymous {
let pretty_name = ty.spelling();
@@ -1238,7 +1228,7 @@ impl Trace for Type {
}
match *self.kind() {
TypeKind::Pointer(inner) |
- TypeKind::Reference(inner, _) |
+ TypeKind::Reference(inner) |
TypeKind::Array(inner, _) |
TypeKind::Vector(inner, _) |
TypeKind::BlockPointer(inner) |
diff --git a/lib.rs b/lib.rs
index e800136..eeb8649 100644
--- a/lib.rs
+++ b/lib.rs
@@ -1,7 +1,5 @@
//! Generate Rust bindings for C and C++ libraries.
//!
-//! This is a slightly forked version for use by `autocxx`.
-//!
//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
//! functions and use types defined in the header.
//!
@@ -54,7 +52,9 @@ mod regex_set;
pub use codegen::{
AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
};
-pub use features::{RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS};
+#[cfg(feature = "__cli")]
+pub use features::RUST_TARGET_STRINGS;
+pub use features::{RustTarget, LATEST_STABLE_RUST};
pub use ir::annotations::FieldVisibilityKind;
pub use ir::function::Abi;
pub use regex_set::RegexSet;
@@ -94,15 +94,15 @@ fn file_is_cpp(name_file: &str) -> bool {
name_file.ends_with(".h++")
}
-fn args_are_cpp(clang_args: &[String]) -> bool {
+fn args_are_cpp(clang_args: &[Box<str>]) -> bool {
for w in clang_args.windows(2) {
- if w[0] == "-xc++" || w[1] == "-xc++" {
+ if w[0].as_ref() == "-xc++" || w[1].as_ref() == "-xc++" {
return true;
}
- if w[0] == "-x" && w[1] == "c++" {
+ if w[0].as_ref() == "-x" && w[1].as_ref() == "c++" {
return true;
}
- if w[0] == "-include" && file_is_cpp(&w[1]) {
+ if w[0].as_ref() == "-include" && file_is_cpp(w[1].as_ref()) {
return true;
}
}
@@ -110,8 +110,8 @@ fn args_are_cpp(clang_args: &[String]) -> bool {
}
bitflags! {
- #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// A type used to indicate which kind of items we have to generate.
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CodegenConfig: u32 {
/// Whether to generate functions.
const FUNCTIONS = 1 << 0;
@@ -265,9 +265,9 @@ impl std::fmt::Display for Formatter {
///
/// # Regular expression arguments
///
-/// Some [`Builder`] methods such as the `allowlist_*` and `blocklist_*` methods allow regular
+/// Some [`Builder`] methods, such as `allowlist_*` and `blocklist_*`, allow regular
/// expressions as arguments. These regular expressions will be enclosed in parentheses and
-/// anchored with `^` and `$`. So if the argument passed is `<regex>`, the regular expression to be
+/// anchored with `^` and `$`. So, if the argument passed is `<regex>`, the regular expression to be
/// stored will be `^(<regex>)$`.
///
/// As a consequence, regular expressions passed to `bindgen` will try to match the whole name of
@@ -275,16 +275,16 @@ impl std::fmt::Display for Formatter {
/// `prefix`, the `prefix.*` regular expression must be used.
///
/// Certain methods, like [`Builder::allowlist_function`], use regular expressions over function
-/// names. To match C++ methods, prefix the name of the type where they belong followed by an
-/// underscore. So if the type `Foo` has a method `bar`, it can be matched with the `Foo_bar`
+/// names. To match C++ methods, prefix the name of the type where they belong, followed by an
+/// underscore. So, if the type `Foo` has a method `bar`, it can be matched with the `Foo_bar`
/// regular expression.
///
/// Additionally, Objective-C interfaces can be matched by prefixing the regular expression with
-/// `I`. For example, the `IFoo` regular expression matches the `Foo` interface and the `IFoo_foo`
+/// `I`. For example, the `IFoo` regular expression matches the `Foo` interface, and the `IFoo_foo`
/// regular expression matches the `foo` method of the `Foo` interface.
///
/// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard
-/// pattern `*` as a valid regular expression. This behavior has been deprecated and the `.*`
+/// pattern `*` as a valid regular expression. This behavior has been deprecated, and the `.*`
/// regular expression must be used instead.
#[derive(Debug, Default, Clone)]
pub struct Builder {
@@ -319,22 +319,31 @@ impl Builder {
/// Generate the Rust bindings using the options built up thus far.
pub fn generate(mut self) -> Result<Bindings, BindgenError> {
// Add any extra arguments from the environment to the clang command line.
- self.options
- .clang_args
- .extend(get_extra_clang_args(&self.options.parse_callbacks));
+ self.options.clang_args.extend(
+ get_extra_clang_args(&self.options.parse_callbacks)
+ .into_iter()
+ .map(String::into_boxed_str),
+ );
+
+ for header in &self.options.input_headers {
+ self.options
+ .for_each_callback(|cb| cb.header_file(header.as_ref()));
+ }
// Transform input headers to arguments on the clang command line.
self.options.clang_args.extend(
self.options.input_headers
[..self.options.input_headers.len().saturating_sub(1)]
.iter()
- .flat_map(|header| ["-include".into(), header.to_string()]),
+ .flat_map(|header| ["-include".into(), header.clone()]),
);
let input_unsaved_files =
std::mem::take(&mut self.options.input_header_contents)
.into_iter()
- .map(|(name, contents)| clang::UnsavedFile::new(name, contents))
+ .map(|(name, contents)| {
+ clang::UnsavedFile::new(name.as_ref(), contents.as_ref())
+ })
.collect::<Vec<_>>();
Bindings::generate(self.options, input_unsaved_files)
@@ -401,7 +410,7 @@ impl Builder {
.stdout(Stdio::piped());
for a in &self.options.clang_args {
- cmd.arg(a);
+ cmd.arg(a.as_ref());
}
for a in get_extra_clang_args(&self.options.parse_callbacks) {
@@ -431,18 +440,19 @@ impl Builder {
impl BindgenOptions {
fn build(&mut self) {
- const REGEX_SETS_LEN: usize = 27;
+ const REGEX_SETS_LEN: usize = 28;
let regex_sets: [_; REGEX_SETS_LEN] = [
- &mut self.allowlisted_vars,
- &mut self.allowlisted_types,
- &mut self.allowlisted_functions,
- &mut self.allowlisted_files,
&mut self.blocklisted_types,
&mut self.blocklisted_functions,
&mut self.blocklisted_items,
&mut self.blocklisted_files,
&mut self.opaque_types,
+ &mut self.allowlisted_vars,
+ &mut self.allowlisted_types,
+ &mut self.allowlisted_functions,
+ &mut self.allowlisted_files,
+ &mut self.allowlisted_items,
&mut self.bitfield_enums,
&mut self.constified_enums,
&mut self.constified_enum_modules,
@@ -478,6 +488,7 @@ impl BindgenOptions {
"--allowlist-function",
"--allowlist-var",
"--allowlist-file",
+ "--allowlist-item",
"--bitfield-enum",
"--newtype-enum",
"--newtype-global-enum",
@@ -560,6 +571,10 @@ impl BindgenOptions {
.collect()
}
+ fn for_each_callback(&self, f: impl Fn(&dyn callbacks::ParseCallbacks)) {
+ self.parse_callbacks.iter().for_each(|cb| f(cb.as_ref()));
+ }
+
fn process_comment(&self, comment: &str) -> String {
let comment = comment::preprocess(comment);
self.parse_callbacks
@@ -570,8 +585,7 @@ impl BindgenOptions {
}
fn deprecated_target_diagnostic(target: RustTarget, _options: &BindgenOptions) {
- let target = String::from(target);
- warn!("The {} Rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", target,);
+ warn!("The {} Rust target is deprecated. If you have a need to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", target);
#[cfg(feature = "experimental")]
if _options.emit_diagnostics {
@@ -669,16 +683,16 @@ pub(crate) const HOST_TARGET: &str =
// Some architecture triplets are different between rust and libclang, see #1211
// and duplicates.
-fn rust_to_clang_target(rust_target: &str) -> String {
+fn rust_to_clang_target(rust_target: &str) -> Box<str> {
if rust_target.starts_with("aarch64-apple-") {
let mut clang_target = "arm64-apple-".to_owned();
clang_target
.push_str(rust_target.strip_prefix("aarch64-apple-").unwrap());
- return clang_target;
+ return clang_target.into();
} else if rust_target.starts_with("riscv64gc-") {
let mut clang_target = "riscv64-".to_owned();
clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap());
- return clang_target;
+ return clang_target.into();
} else if rust_target.ends_with("-espidf") {
let mut clang_target =
rust_target.strip_suffix("-espidf").unwrap().to_owned();
@@ -687,23 +701,32 @@ fn rust_to_clang_target(rust_target: &str) -> String {
clang_target = "riscv32-".to_owned() +
clang_target.strip_prefix("riscv32imc-").unwrap();
}
- return clang_target;
+ return clang_target.into();
+ } else if rust_target.starts_with("riscv32imc-") {
+ let mut clang_target = "riscv32-".to_owned();
+ clang_target.push_str(rust_target.strip_prefix("riscv32imc-").unwrap());
+ return clang_target.into();
+ } else if rust_target.starts_with("riscv32imac-") {
+ let mut clang_target = "riscv32-".to_owned();
+ clang_target
+ .push_str(rust_target.strip_prefix("riscv32imac-").unwrap());
+ return clang_target.into();
}
- rust_target.to_owned()
+ rust_target.into()
}
/// Returns the effective target, and whether it was explicitly specified on the
/// clang flags.
-fn find_effective_target(clang_args: &[String]) -> (String, bool) {
+fn find_effective_target(clang_args: &[Box<str>]) -> (Box<str>, bool) {
let mut args = clang_args.iter();
while let Some(opt) = args.next() {
if opt.starts_with("--target=") {
let mut split = opt.split('=');
split.next();
- return (split.next().unwrap().to_owned(), true);
+ return (split.next().unwrap().into(), true);
}
- if opt == "-target" {
+ if opt.as_ref() == "-target" {
if let Some(target) = args.next() {
return (target.clone(), true);
}
@@ -748,9 +771,10 @@ impl Bindings {
// opening libclang.so, it has to be the same architecture and thus the
// check is fine.
if !explicit_target && !is_host_build {
- options
- .clang_args
- .insert(0, format!("--target={}", effective_target));
+ options.clang_args.insert(
+ 0,
+ format!("--target={}", effective_target).into_boxed_str(),
+ );
};
fn detect_include_paths(options: &mut BindgenOptions) {
@@ -771,7 +795,7 @@ impl Bindings {
return false;
}
- let arg = &**arg;
+ let arg = arg.as_ref();
// https://clang.llvm.org/docs/ClangCommandLineReference.html
// -isystem and -isystem-after are harmless.
@@ -788,7 +812,7 @@ impl Bindings {
true
})
- .cloned()
+ .map(|arg| arg.clone().into())
.collect::<Vec<_>>()
};
@@ -820,8 +844,8 @@ impl Bindings {
if let Some(search_paths) = search_paths {
for path in search_paths.into_iter() {
if let Ok(path) = path.into_os_string().into_string() {
- options.clang_args.push("-isystem".to_owned());
- options.clang_args.push(path);
+ options.clang_args.push("-isystem".into());
+ options.clang_args.push(path.into_boxed_str());
}
}
}
@@ -841,7 +865,7 @@ impl Bindings {
}
if let Some(h) = options.input_headers.last() {
- let path = Path::new(h);
+ let path = Path::new(h.as_ref());
if let Ok(md) = std::fs::metadata(path) {
if md.is_dir() {
return Err(BindgenError::FolderAsHeader(path.into()));
@@ -851,8 +875,7 @@ impl Bindings {
path.into(),
));
}
- let h = h.clone();
- options.clang_args.push(h);
+ options.clang_args.push(h.clone());
} else {
return Err(BindgenError::NotExist(path.into()));
}
@@ -860,9 +883,9 @@ impl Bindings {
for (idx, f) in input_unsaved_files.iter().enumerate() {
if idx != 0 || !options.input_headers.is_empty() {
- options.clang_args.push("-include".to_owned());
+ options.clang_args.push("-include".into());
}
- options.clang_args.push(f.name.to_str().unwrap().to_owned())
+ options.clang_args.push(f.name.to_str().unwrap().into())
}
debug!("Fixed-up options: {:?}", options);
@@ -905,10 +928,10 @@ impl Bindings {
/// Write these bindings as source text to the given `Write`able.
pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
if !self.options.disable_header_comment {
- let version = Some("0.65.1");
+ let version =
+ Some("0.69.1").unwrap_or("(unknown version)");
let header = format!(
- "/* automatically generated by rust-bindgen {} */\n\n",
- version.unwrap_or("(unknown version)")
+ "/* automatically generated by rust-bindgen {version} */\n\n",
);
writer.write_all(header.as_bytes())?;
}
@@ -969,7 +992,6 @@ impl Bindings {
match self.options.formatter {
Formatter::None => return Ok(tokens.to_string()),
-
#[cfg(feature = "prettyplease")]
Formatter::Prettyplease => {
return Ok(prettyplease::unparse(&syn::parse_quote!(#tokens)));
@@ -1078,20 +1100,19 @@ fn parse_one(
ctx: &mut BindgenContext,
cursor: clang::Cursor,
parent: Option<ItemId>,
-) -> clang_sys::CXChildVisitResult {
+) {
if !filter_builtins(ctx, &cursor) {
- return CXChildVisit_Continue;
+ return;
}
- use clang_sys::CXChildVisit_Continue;
match Item::parse(cursor, parent, ctx) {
Ok(..) => {}
Err(ParseError::Continue) => {}
Err(ParseError::Recurse) => {
- cursor.visit(|child| parse_one(ctx, child, parent));
+ cursor
+ .visit_sorted(ctx, |ctx, child| parse_one(ctx, child, parent));
}
}
- CXChildVisit_Continue
}
/// Parse the Clang AST into our `Item` internal representation.
@@ -1129,8 +1150,8 @@ fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> {
}
let root = context.root_module();
- context.with_module(root, |context| {
- cursor.visit(|cursor| parse_one(context, cursor, None))
+ context.with_module(root, |ctx| {
+ cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, None))
});
assert!(
@@ -1213,7 +1234,6 @@ fn get_target_dependent_env_var(
/// When running inside a `build.rs` script, this can be used to make cargo invalidate the
/// generated bindings whenever any of the files included from the header change:
/// ```
-/// use autocxx_bindgen as bindgen;
/// use bindgen::builder;
/// let bindings = builder()
/// .header("path/to/input/header")
@@ -1221,9 +1241,50 @@ fn get_target_dependent_env_var(
/// .generate();
/// ```
#[derive(Debug)]
-pub struct CargoCallbacks;
+pub struct CargoCallbacks {
+ rerun_on_header_files: bool,
+}
+
+/// Create a new `CargoCallbacks` value with [`CargoCallbacks::rerun_on_header_files`] disabled.
+///
+/// This constructor has been deprecated in favor of [`CargoCallbacks::new`] where
+/// [`CargoCallbacks::rerun_on_header_files`] is enabled by default.
+#[deprecated = "Use `CargoCallbacks::new()` instead. Please, check the documentation for further information."]
+pub const CargoCallbacks: CargoCallbacks = CargoCallbacks {
+ rerun_on_header_files: false,
+};
+
+impl CargoCallbacks {
+ /// Create a new `CargoCallbacks` value.
+ pub fn new() -> Self {
+ Self {
+ rerun_on_header_files: true,
+ }
+ }
+
+ /// Whether Cargo should re-run the build script if any of the input header files has changed.
+ ///
+ /// This option is enabled by default unless the deprecated [`const@CargoCallbacks`]
+ /// constructor is used.
+ pub fn rerun_on_header_files(mut self, doit: bool) -> Self {
+ self.rerun_on_header_files = doit;
+ self
+ }
+}
+
+impl Default for CargoCallbacks {
+ fn default() -> Self {
+ Self::new()
+ }
+}
impl callbacks::ParseCallbacks for CargoCallbacks {
+ fn header_file(&self, filename: &str) {
+ if self.rerun_on_header_files {
+ println!("cargo:rerun-if-changed={}", filename);
+ }
+ }
+
fn include_file(&self, filename: &str) {
println!("cargo:rerun-if-changed={}", filename);
}
@@ -1240,7 +1301,7 @@ fn commandline_flag_unit_test_function() {
let bindings = crate::builder();
let command_line_flags = bindings.command_line_flags();
- let test_cases = vec![
+ let test_cases = [
"--rust-target",
"--no-derive-default",
"--generate",
@@ -1259,7 +1320,7 @@ fn commandline_flag_unit_test_function() {
.allowlist_function("safe_function");
let command_line_flags = bindings.command_line_flags();
- let test_cases = vec![
+ let test_cases = [
"--rust-target",
"input_header",
"--no-derive-default",
@@ -1280,25 +1341,36 @@ fn commandline_flag_unit_test_function() {
#[test]
fn test_rust_to_clang_target() {
- assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios");
+ assert_eq!(
+ rust_to_clang_target("aarch64-apple-ios").as_ref(),
+ "arm64-apple-ios"
+ );
}
#[test]
fn test_rust_to_clang_target_riscv() {
assert_eq!(
- rust_to_clang_target("riscv64gc-unknown-linux-gnu"),
+ rust_to_clang_target("riscv64gc-unknown-linux-gnu").as_ref(),
"riscv64-unknown-linux-gnu"
- )
+ );
+ assert_eq!(
+ rust_to_clang_target("riscv32imc-unknown-none-elf").as_ref(),
+ "riscv32-unknown-none-elf"
+ );
+ assert_eq!(
+ rust_to_clang_target("riscv32imac-unknown-none-elf").as_ref(),
+ "riscv32-unknown-none-elf"
+ );
}
#[test]
fn test_rust_to_clang_target_espidf() {
assert_eq!(
- rust_to_clang_target("riscv32imc-esp-espidf"),
+ rust_to_clang_target("riscv32imc-esp-espidf").as_ref(),
"riscv32-esp-elf"
);
assert_eq!(
- rust_to_clang_target("xtensa-esp32-espidf"),
+ rust_to_clang_target("xtensa-esp32-espidf").as_ref(),
"xtensa-esp32-elf"
);
}
diff --git a/options/as_args.rs b/options/as_args.rs
index 13439c4..6918ad9 100644
--- a/options/as_args.rs
+++ b/options/as_args.rs
@@ -24,7 +24,7 @@ impl AsArgs for bool {
impl AsArgs for RegexSet {
fn as_args(&self, args: &mut Vec<String>, flag: &str) {
for item in self.get_items() {
- args.extend_from_slice(&[flag.to_owned(), item.clone()]);
+ args.extend_from_slice(&[flag.to_owned(), item.clone().into()]);
}
}
}
diff --git a/options/mod.rs b/options/mod.rs
index 54b44eb..3a82bcf 100644
--- a/options/mod.rs
+++ b/options/mod.rs
@@ -114,7 +114,7 @@ macro_rules! options {
let headers = match self.options.input_headers.split_last() {
Some((header, headers)) => {
// The last input header is passed as an argument in the first position.
- args.push(header.clone());
+ args.push(header.clone().into());
headers
},
None => &[]
@@ -135,13 +135,13 @@ macro_rules! options {
args.push("--".to_owned());
if !self.options.clang_args.is_empty() {
- args.extend_from_slice(&self.options.clang_args);
+ args.extend(self.options.clang_args.iter().map(|s| s.clone().into()));
}
// We need to pass all but the last header via the `-include` clang argument.
for header in headers {
args.push("-include".to_owned());
- args.push(header.clone());
+ args.push(header.clone().into());
}
args
@@ -153,66 +153,14 @@ macro_rules! options {
}
options! {
- /// Whether to specify the type of a virtual function receiver
- use_specific_virtual_function_receiver: bool {
- methods: {
- /// Normally, virtual functions have void* as their 'this' type.
- /// If this flag is enabled, override that behavior to indicate a
- /// pointer of the specific type.
- /// Disabled by default.
- pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder {
- self.options.use_specific_virtual_function_receiver = doit;
- self
- }
- },
- as_args: "--use-specific-virtual-function-receiver",
- },
-
- /// Whether we should emit C++ semantics attributes.
- cpp_semantic_attributes: bool {
- methods: {
- /// If this is true, add attributes with details of underlying C++ semantics.
- /// Disabled by default.
- pub fn cpp_semantic_attributes(mut self, doit: bool) -> Builder {
- self.options.cpp_semantic_attributes = doit;
- self
- }
- },
- as_args: "--cpp-semantic-attributes",
- },
-
- /// Whether we should output information about C++ overloaded operators.
- represent_cxx_operators: bool {
- methods: {
- /// If this is true, output existence of C++ overloaded operators.
- /// At present, only operator= is noted.
- /// Disabled by default.
- pub fn represent_cxx_operators(mut self, doit: bool) -> Builder {
- self.options.represent_cxx_operators = doit;
- self
- }
- },
- as_args: "--represent-cxx-operators",
- },
-
- /// Whether we should distinguish between 'char16_t' and 'u16'
- use_distinct_char16_t: bool {
- methods: {
- /// If this is true, denote 'char16_t' as a separate type from 'u16'
- /// Disabled by default.
- pub fn use_distinct_char16_t(mut self, doit: bool) -> Builder {
- self.options.use_distinct_char16_t = doit;
- self
- }
- },
- as_args: "--use-distinct-char16-t",
- },
-
/// Types that have been blocklisted and should not appear anywhere in the generated code.
blocklisted_types: RegexSet {
methods: {
regex_option! {
/// Do not generate any bindings for the given type.
+ ///
+ /// This option is not recursive, meaning that it will only block types whose names
+ /// explicitly match the argument of this method.
pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.blocklisted_types.insert(arg);
self
@@ -226,6 +174,9 @@ options! {
methods: {
regex_option! {
/// Do not generate any bindings for the given function.
+ ///
+ /// This option is not recursive, meaning that it will only block functions whose
+ /// names explicitly match the argument of this method.
pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.blocklisted_functions.insert(arg);
self
@@ -240,6 +191,9 @@ options! {
regex_option! {
/// Do not generate any bindings for the given item, regardless of whether it is a
/// type, function, module, etc.
+ ///
+ /// This option is not recursive, meaning that it will only block items whose names
+ /// explicitly match the argument of this method.
pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.blocklisted_items.insert(arg);
self
@@ -254,6 +208,12 @@ options! {
regex_option! {
/// Do not generate any bindings for the contents of the given file, regardless of
/// whether the contents of the file are types, functions, modules, etc.
+ ///
+ /// This option is not recursive, meaning that it will only block files whose names
+ /// explicitly match the argument of this method.
+ ///
+ /// This method will use the argument to match the complete path of the file
+ /// instead of a section of it.
pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.blocklisted_files.insert(arg);
self
@@ -374,6 +334,9 @@ options! {
///
/// This option is transitive by default. Check the documentation of the
/// [`Builder::allowlist_recursively`] method for further information.
+ ///
+ /// This method will use the argument to match the complete path of the file
+ /// instead of a section of it.
pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.allowlisted_files.insert(arg);
self
@@ -382,6 +345,23 @@ options! {
},
as_args: "--allowlist-file",
},
+ /// Items that have been allowlisted and should appear in the generated code.
+ allowlisted_items: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the given item, regardless of whether it is a type,
+ /// function, module, etc.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ pub fn allowlist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_items.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-item",
+ },
/// The default style of for generated `enum`s.
default_enum_style: EnumVariation {
methods: {
@@ -1109,24 +1089,24 @@ options! {
as_args: |value, args| (!value).as_args(args, "--no-convert-floats"),
},
/// The set of raw lines to be prepended to the top-level module of the generated Rust code.
- raw_lines: Vec<String> {
+ raw_lines: Vec<Box<str>> {
methods: {
/// Add a line of Rust code at the beginning of the generated bindings. The string is
/// passed through without any modification.
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.raw_lines.push(arg.into());
+ self.options.raw_lines.push(arg.into().into_boxed_str());
self
}
},
as_args: |raw_lines, args| {
for line in raw_lines {
args.push("--raw-line".to_owned());
- args.push(line.clone());
+ args.push(line.clone().into());
}
},
},
/// The set of raw lines to prepend to different modules.
- module_lines: HashMap<String, Vec<String>> {
+ module_lines: HashMap<Box<str>, Vec<Box<str>>> {
methods: {
/// Add a given line to the beginning of a given module.
///
@@ -1139,9 +1119,9 @@ options! {
{
self.options
.module_lines
- .entry(module.into())
- .or_insert_with(Vec::new)
- .push(line.into());
+ .entry(module.into().into_boxed_str())
+ .or_default()
+ .push(line.into().into_boxed_str());
self
}
},
@@ -1149,14 +1129,14 @@ options! {
for (module, lines) in module_lines {
for line in lines.iter() {
args.push("--module-raw-line".to_owned());
- args.push(module.clone());
- args.push(line.clone());
+ args.push(module.clone().into());
+ args.push(line.clone().into());
}
}
},
},
/// The input header files.
- input_headers: Vec<String> {
+ input_headers: Vec<Box<str>> {
methods: {
/// Add an input C/C++ header to generate bindings for.
///
@@ -1180,7 +1160,7 @@ options! {
/// .unwrap();
/// ```
pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
- self.options.input_headers.push(header.into());
+ self.options.input_headers.push(header.into().into_boxed_str());
self
}
},
@@ -1188,11 +1168,11 @@ options! {
as_args: ignore,
},
/// The set of arguments to be passed straight through to Clang.
- clang_args: Vec<String> {
+ clang_args: Vec<Box<str>> {
methods: {
/// Add an argument to be passed straight through to Clang.
pub fn clang_arg<T: Into<String>>(self, arg: T) -> Builder {
- self.clang_args([arg.into()])
+ self.clang_args([arg.into().into_boxed_str()])
}
/// Add several arguments to be passed straight through to Clang.
@@ -1201,7 +1181,7 @@ options! {
I::Item: AsRef<str>,
{
for arg in args {
- self.options.clang_args.push(arg.as_ref().to_owned());
+ self.options.clang_args.push(arg.as_ref().to_owned().into_boxed_str());
}
self
}
@@ -1210,7 +1190,7 @@ options! {
as_args: ignore,
},
/// Tuples of unsaved file contents of the form (name, contents).
- input_header_contents: Vec<(String, String)> {
+ input_header_contents: Vec<(Box<str>, Box<str>)> {
methods: {
/// Add `contents` as an input C/C++ header named `name`.
///
@@ -1224,7 +1204,7 @@ options! {
.join(name)
.to_str()
.expect("Cannot convert current directory name to string")
- .to_owned();
+ .into();
self.options
.input_header_contents
.push((absolute_path, contents.into()));
@@ -1394,7 +1374,7 @@ options! {
/// or `-fno-inline-functions` if you are responsible of compiling the library to make
/// them callable.
#[cfg_attr(
- features = "experimental",
+ feature = "experimental",
doc = "\nCheck the [`Builder::wrap_static_fns`] method for an alternative."
)]
pub fn generate_inline_functions(mut self, doit: bool) -> Self {
@@ -1471,6 +1451,23 @@ options! {
},
as_args: "--generate-block",
},
+ /// Whether to generate strings as `CStr`.
+ generate_cstr: bool {
+ methods: {
+ /// Set whether string constants should be generated as `&CStr` instead of `&[u8]`.
+ ///
+ /// A minimum Rust target of 1.59 is required for this to have any effect as support
+ /// for `CStr::from_bytes_with_nul_unchecked` in `const` contexts is needed.
+ ///
+ /// This option is disabled by default but will become enabled by default in a future
+ /// release, so enabling this is recommended.
+ pub fn generate_cstr(mut self, doit: bool) -> Self {
+ self.options.generate_cstr = doit;
+ self
+ }
+ },
+ as_args: "--generate-cstr",
+ },
/// Whether to emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue
/// of the files generated from apple block files.
block_extern_crate: bool {
@@ -1563,7 +1560,7 @@ options! {
},
as_args: |rust_target, args| {
args.push("--rust-target".to_owned());
- args.push((*rust_target).into());
+ args.push(rust_target.to_string());
},
},
/// Features to be enabled. They are derived from `rust_target`.
@@ -1609,6 +1606,9 @@ options! {
methods: {
/// Set whether `size_t` should be translated to `usize`.
///
+ /// If `size_t` is translated to `usize`, type definitions for `size_t` will not be
+ /// emitted.
+ ///
/// `size_t` is translated to `usize` by default.
pub fn size_t_is_usize(mut self, is: bool) -> Self {
self.options.size_t_is_usize = is;
diff --git a/patches/autocxx.patch b/patches/autocxx.patch
deleted file mode 100644
index 256b928..0000000
--- a/patches/autocxx.patch
+++ /dev/null
@@ -1,2190 +0,0 @@
-diff --git a/Android.bp b/Android.bp
-index 0f0d867..af0cb35 100644
---- a/Android.bp
-+++ b/Android.bp
-@@ -66,6 +66,7 @@ rust_library_host {
- "libpeeking_take_while",
- "libprettyplease",
- "libproc_macro2",
-+ "libitertools",
- "libquote",
- "libregex",
- "librustc_hash",
-diff --git a/clang.rs b/clang.rs
-index 0060213..4f8de24 100644
---- a/clang.rs
-+++ b/clang.rs
-@@ -833,6 +833,21 @@ impl Cursor {
- unsafe { clang_isVirtualBase(self.x) != 0 }
- }
-
-+ // Is this cursor's referent a default constructor?
-+ pub fn is_default_constructor(&self) -> bool {
-+ unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 }
-+ }
-+
-+ // Is this cursor's referent a copy constructor?
-+ pub fn is_copy_constructor(&self) -> bool {
-+ unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 }
-+ }
-+
-+ // Is this cursor's referent a move constructor?
-+ pub fn is_move_constructor(&self) -> bool {
-+ unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 }
-+ }
-+
- /// Try to evaluate this cursor.
- pub(crate) fn evaluate(&self) -> Option<EvalResult> {
- EvalResult::new(*self)
-diff --git a/codegen/error.rs b/codegen/error.rs
-index ead3496..f38a1c6 100644
---- a/codegen/error.rs
-+++ b/codegen/error.rs
-@@ -11,6 +11,9 @@ pub(crate) enum Error {
- /// definition that is too difficult for us to understand (like a partial
- /// template specialization).
- InstantiationOfOpaqueType,
-+
-+ /// Type was a reference not a pointer, but we had nowhere to record that fact.
-+ ReferenceButCouldNotRecord,
- }
-
- impl fmt::Display for Error {
-@@ -23,6 +26,9 @@ impl fmt::Display for Error {
- "Instantiation of opaque template type or partial template \
- specialization"
- }
-+ Error::ReferenceButCouldNotRecord => {
-+ "Type was a reference in a context where we only expected other types"
-+ }
- })
- }
- }
-diff --git a/codegen/helpers.rs b/codegen/helpers.rs
-index 726fe75..113e93d 100644
---- a/codegen/helpers.rs
-+++ b/codegen/helpers.rs
-@@ -1,7 +1,9 @@
- //! Helpers for code generation that don't need macro expansion.
-
--use crate::ir::context::BindgenContext;
-+use crate::ir::comp::SpecialMemberKind;
-+use crate::ir::function::Visibility;
- use crate::ir::layout::Layout;
-+use crate::{ir::context::BindgenContext, BindgenOptions};
- use proc_macro2::{Ident, Span, TokenStream};
- use quote::TokenStreamExt;
-
-@@ -77,6 +79,173 @@ pub(crate) mod attributes {
- }
- }
-
-+pub trait CppSemanticAttributeCreator {
-+ fn do_add(&mut self, ts: TokenStream);
-+ fn is_enabled(&self) -> bool;
-+
-+ fn add(&mut self, tokens: TokenStream) {
-+ if self.is_enabled() {
-+ self.do_add(quote! {
-+ #[cpp_semantics(#tokens)]
-+ })
-+ }
-+ }
-+
-+ fn add_ident(&mut self, desc: &str) {
-+ if self.is_enabled() {
-+ let id = Ident::new(desc, Span::call_site());
-+ self.add(quote! { #id })
-+ }
-+ }
-+
-+ fn special_member(&mut self, kind: SpecialMemberKind) {
-+ let kind_str = match kind {
-+ SpecialMemberKind::DefaultConstructor => "default_ctor",
-+ SpecialMemberKind::CopyConstructor => "copy_ctor",
-+ SpecialMemberKind::MoveConstructor => "move_ctor",
-+ SpecialMemberKind::Destructor => "dtor",
-+ SpecialMemberKind::AssignmentOperator => "assignment_operator",
-+ };
-+ self.add(quote! {
-+ special_member(#kind_str)
-+ })
-+ }
-+
-+ fn original_name(&mut self, name: &str) {
-+ self.add(quote! {
-+ original_name(#name)
-+ })
-+ }
-+
-+ fn ret_type_reference(&mut self) {
-+ self.add_ident("ret_type_reference")
-+ }
-+
-+ fn ret_type_rvalue_reference(&mut self) {
-+ self.add_ident("ret_type_rvalue_reference")
-+ }
-+
-+ fn arg_type_reference(&mut self, arg_name: &Ident) {
-+ self.add(quote! {
-+ arg_type_reference(#arg_name)
-+ })
-+ }
-+
-+ fn field_type_reference(&mut self) {
-+ self.add_ident("reference")
-+ }
-+
-+ fn field_type_rvalue_reference(&mut self) {
-+ self.add_ident("rvalue_reference")
-+ }
-+
-+ fn is_virtual(&mut self) {
-+ self.add_ident("bindgen_virtual")
-+ }
-+
-+ fn arg_type_rvalue_reference(&mut self, arg_name: &Ident) {
-+ self.add(quote! {
-+ arg_type_rvalue_reference(#arg_name)
-+ })
-+ }
-+
-+ fn is_pure_virtual(&mut self) {
-+ self.add_ident("pure_virtual")
-+ }
-+
-+ fn visibility(&mut self, visibility: Visibility) {
-+ match visibility {
-+ Visibility::Protected => self.add_ident("visibility_protected"),
-+ Visibility::Private => self.add_ident("visibility_private"),
-+ _ => {}
-+ }
-+ }
-+
-+ fn incomprehensible_param_in_arg_or_return(&mut self) {
-+ self.add_ident("incomprehensible_param_in_arg_or_return")
-+ }
-+
-+ fn discards_template_param(&mut self) {
-+ self.add_ident("unused_template_param")
-+ }
-+
-+ fn deleted_fn(&mut self) {
-+ self.add_ident("deleted")
-+ }
-+
-+ fn defaulted_fn(&mut self) {
-+ self.add_ident("defaulted")
-+ }
-+
-+ fn layout(&mut self, layout: &Layout) {
-+ let sz = ast_ty::int_expr(layout.size as i64);
-+ let align = ast_ty::int_expr(layout.align as i64);
-+ let packed = if layout.packed {
-+ quote! { true }
-+ } else {
-+ quote! { false }
-+ };
-+ self.add(quote! {
-+ layout(#sz, #align, #packed)
-+ })
-+ }
-+}
-+
-+pub struct CppSemanticAttributeAdder<'a> {
-+ enabled: bool,
-+ attrs: &'a mut Vec<TokenStream>,
-+}
-+
-+impl<'a> CppSemanticAttributeAdder<'a> {
-+ pub(crate) fn new(
-+ opts: &BindgenOptions,
-+ attrs: &'a mut Vec<TokenStream>,
-+ ) -> Self {
-+ Self {
-+ enabled: opts.cpp_semantic_attributes,
-+ attrs,
-+ }
-+ }
-+}
-+
-+impl<'a> CppSemanticAttributeCreator for CppSemanticAttributeAdder<'a> {
-+ fn do_add(&mut self, ts: TokenStream) {
-+ self.attrs.push(ts)
-+ }
-+
-+ fn is_enabled(&self) -> bool {
-+ self.enabled
-+ }
-+}
-+
-+pub struct CppSemanticAttributeSingle {
-+ enabled: bool,
-+ attr: TokenStream,
-+}
-+
-+impl CppSemanticAttributeSingle {
-+ pub(crate) fn new(opts: &BindgenOptions) -> Self {
-+ Self {
-+ enabled: opts.cpp_semantic_attributes,
-+ attr: quote! {},
-+ }
-+ }
-+
-+ pub(crate) fn result(self) -> TokenStream {
-+ self.attr
-+ }
-+}
-+
-+impl CppSemanticAttributeCreator for CppSemanticAttributeSingle {
-+ fn do_add(&mut self, ts: TokenStream) {
-+ self.attr = ts;
-+ }
-+
-+ fn is_enabled(&self) -> bool {
-+ self.enabled
-+ }
-+}
-+
- /// Generates a proper type for a field or type with a given `Layout`, that is,
- /// a type with the correct size and alignment restrictions.
- pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
-diff --git a/codegen/mod.rs b/codegen/mod.rs
-index 0dd3228..41f6e3a 100644
---- a/codegen/mod.rs
-+++ b/codegen/mod.rs
-@@ -20,6 +20,10 @@ use self::struct_layout::StructLayoutTracker;
- use super::BindgenOptions;
-
- use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind};
-+use crate::codegen::helpers::{
-+ CppSemanticAttributeAdder, CppSemanticAttributeCreator,
-+ CppSemanticAttributeSingle,
-+};
- use crate::ir::analysis::{HasVtable, Sizedness};
- use crate::ir::annotations::{
- Annotations, FieldAccessorKind, FieldVisibilityKind,
-@@ -441,12 +445,13 @@ impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
- _ => {}
- }
-
-- let params: Vec<_> = item
-- .used_template_params(ctx)
-+ let (used_template_params, _) = item.used_template_params(ctx);
-+ let params: Vec<_> = used_template_params
- .iter()
- .map(|p| {
- p.try_to_rust_ty(ctx, &())
- .expect("template params cannot fail to be a rust type")
-+ .ignore_annotations()
- })
- .collect();
- if !params.is_empty() {
-@@ -662,7 +667,10 @@ impl CodeGenerator for Var {
- attrs.push(attributes::doc(comment));
- }
-
-- let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
-+ let ty = self
-+ .ty()
-+ .to_rust_ty_or_opaque(ctx, &())
-+ .ignore_annotations();
-
- if let Some(val) = self.val() {
- match *val {
-@@ -904,7 +912,8 @@ impl CodeGenerator for Type {
- return;
- }
-
-- let mut outer_params = item.used_template_params(ctx);
-+ let (mut outer_params, has_unused_template_args) =
-+ item.used_template_params(ctx);
-
- let is_opaque = item.is_opaque(ctx, &());
- let inner_rust_type = if is_opaque {
-@@ -914,9 +923,12 @@ impl CodeGenerator for Type {
- // Its possible that we have better layout information than
- // the inner type does, so fall back to an opaque blob based
- // on our layout if converting the inner item fails.
-- let mut inner_ty = inner_item
-+ let (mut inner_ty, _) = inner_item
- .try_to_rust_ty_or_opaque(ctx, &())
-- .unwrap_or_else(|_| self.to_opaque(ctx, item));
-+ .map(|ty| ty.into_outer_type())
-+ .unwrap_or_else(|_| {
-+ (self.to_opaque(ctx, item), RustTyAnnotation::None)
-+ });
- inner_ty.append_implicit_template_params(ctx, inner_item);
- inner_ty
- };
-@@ -951,6 +963,18 @@ impl CodeGenerator for Type {
- } else {
- quote! {}
- };
-+ let mut semantic_annotations =
-+ CppSemanticAttributeSingle::new(ctx.options());
-+ // We are handling (essentially) type X = Y;
-+ // We want to denote only if X has unused template params, e.g.
-+ // type X<A> = Y;
-+ // We don't want to note whether Y has unused template params, e.g.
-+ // type X = Y<B>
-+ // because that information will be recorded against the definition of Y.
-+ if has_unused_template_args {
-+ semantic_annotations.discards_template_param();
-+ }
-+ tokens.append_all(semantic_annotations.result());
-
- let alias_style = if ctx.options().type_alias.matches(&name) {
- AliasVariation::TypeAlias
-@@ -983,8 +1007,21 @@ impl CodeGenerator for Type {
- return;
- }
-
-+ let mut attributes = Vec::new();
-+ if let Some(original_name) = item.original_name(ctx) {
-+ if name != original_name {
-+ let mut semantic_annotations =
-+ CppSemanticAttributeAdder::new(
-+ ctx.options(),
-+ &mut attributes,
-+ );
-+ semantic_annotations.original_name(&original_name);
-+ }
-+ }
-+
- tokens.append_all(match alias_style {
- AliasVariation::TypeAlias => quote! {
-+ #( #attributes )*
- pub type #rust_name
- },
- AliasVariation::NewType | AliasVariation::NewTypeDeref => {
-@@ -1031,7 +1068,7 @@ impl CodeGenerator for Type {
- .map(|p| {
- p.try_to_rust_ty(ctx, &()).expect(
- "type parameters can always convert to rust ty OK",
-- )
-+ ).ignore_annotations()
- })
- .collect();
-
-@@ -1147,8 +1184,8 @@ impl<'a> CodeGenerator for Vtable<'a> {
-
- // FIXME: Need to account for overloading with times_seen (separately from regular function path).
- let function_name = ctx.rust_ident(function_name);
-- let mut args = utils::fnsig_arguments(ctx, signature);
-- let ret = utils::fnsig_return_ty(ctx, signature);
-+ let (mut args, _) = utils::fnsig_arguments(ctx, signature);
-+ let (ret, _) = utils::fnsig_return_ty(ctx, signature);
-
- args[0] = if m.is_const() {
- quote! { this: *const #class_ident }
-@@ -1193,11 +1230,12 @@ impl<'a> TryToRustTy for Vtable<'a> {
- &self,
- ctx: &BindgenContext,
- _: &(),
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- let name = ctx.rust_ident(self.canonical_name(ctx));
- Ok(quote! {
- #name
-- })
-+ }
-+ .into())
- }
- }
-
-@@ -1247,7 +1285,8 @@ impl CodeGenerator for TemplateInstantiation {
- let fn_name = ctx.rust_ident_raw(fn_name);
-
- let prefix = ctx.trait_prefix();
-- let ident = item.to_rust_ty_or_opaque(ctx, &());
-+ let ident =
-+ item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
- let size_of_expr = quote! {
- ::#prefix::mem::size_of::<#ident>()
- };
-@@ -1396,7 +1435,8 @@ impl<'a> FieldCodegen<'a> for FieldData {
- let field_item =
- self.ty().into_resolver().through_type_refs().resolve(ctx);
- let field_ty = field_item.expect_type();
-- let mut ty = self.ty().to_rust_ty_or_opaque(ctx, &());
-+ let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
-+ let (mut ty, ty_annotations) = ty.into_outer_type();
- ty.append_implicit_template_params(ctx, field_item);
-
- // NB: If supported, we use proper `union` types.
-@@ -1405,7 +1445,8 @@ impl<'a> FieldCodegen<'a> for FieldData {
- } else if let Some(item) = field_ty.is_incomplete_array(ctx) {
- result.saw_incomplete_array();
-
-- let inner = item.to_rust_ty_or_opaque(ctx, &());
-+ let inner =
-+ item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
-
- if ctx.options().enable_cxx_namespaces {
- quote! {
-@@ -1449,19 +1490,33 @@ impl<'a> FieldCodegen<'a> for FieldData {
- let accessor_kind =
- self.annotations().accessor_kind().unwrap_or(accessor_kind);
-
-+ let mut attributes = Vec::new();
-+ let mut csaa =
-+ CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
-+ match ty_annotations {
-+ RustTyAnnotation::Reference => csaa.field_type_reference(),
-+ RustTyAnnotation::RValueReference => {
-+ csaa.field_type_rvalue_reference()
-+ }
-+ _ => {}
-+ };
-+
- match visibility {
- FieldVisibilityKind::Private => {
- field.append_all(quote! {
-+ #(#attributes),*
- #field_ident : #ty ,
- });
- }
- FieldVisibilityKind::PublicCrate => {
- field.append_all(quote! {
-+ #(#attributes),*
- pub(crate) #field_ident : #ty ,
- });
- }
- FieldVisibilityKind::Public => {
- field.append_all(quote! {
-+ #(#attributes),*
- pub #field_ident : #ty ,
- });
- }
-@@ -1723,8 +1778,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
- let param_name = bitfield_getter_name(ctx, bf);
- let bitfield_ty_item = ctx.resolve_item(bf.ty());
- let bitfield_ty = bitfield_ty_item.expect_type();
-- let bitfield_ty =
-- bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
-+ let bitfield_ty = bitfield_ty
-+ .to_rust_ty_or_opaque(ctx, bitfield_ty_item)
-+ .ignore_annotations();
-
- ctor_params.push(quote! {
- #param_name : #bitfield_ty
-@@ -1819,8 +1875,9 @@ impl<'a> FieldCodegen<'a> for Bitfield {
- }
- };
-
-- let bitfield_ty =
-- bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
-+ let bitfield_ty = bitfield_ty
-+ .to_rust_ty_or_opaque(ctx, bitfield_ty_item)
-+ .ignore_annotations();
-
- let offset = self.offset_into_unit();
- let width = self.width() as u8;
-@@ -1936,6 +1993,7 @@ impl CodeGenerator for CompInfo {
- let vtable_type = vtable
- .try_to_rust_ty(ctx, &())
- .expect("vtable to Rust type conversion is infallible")
-+ .ignore_annotations()
- .to_ptr(true);
-
- fields.push(quote! {
-@@ -1951,7 +2009,9 @@ impl CodeGenerator for CompInfo {
- }
-
- let inner_item = ctx.resolve_item(base.ty);
-- let mut inner = inner_item.to_rust_ty_or_opaque(ctx, &());
-+ let mut inner = inner_item
-+ .to_rust_ty_or_opaque(ctx, &())
-+ .ignore_annotations();
- inner.append_implicit_template_params(ctx, inner_item);
- let field_name = ctx.rust_ident(&base.field_name);
-
-@@ -2115,7 +2175,9 @@ impl CodeGenerator for CompInfo {
-
- let mut generic_param_names = vec![];
-
-- for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
-+ let (used_template_params, unused_template_params) =
-+ item.used_template_params(ctx);
-+ for (idx, ty) in used_template_params.iter().enumerate() {
- let param = ctx.resolve_type(*ty);
- let name = param.name().unwrap();
- let ident = ctx.rust_ident(name);
-@@ -2159,6 +2221,15 @@ impl CodeGenerator for CompInfo {
- } else {
- attributes.push(attributes::repr("C"));
- }
-+ let mut semantic_annotations =
-+ CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
-+ if unused_template_params {
-+ semantic_annotations.discards_template_param();
-+ }
-+ semantic_annotations.visibility(self.visibility());
-+ if let Some(layout) = layout {
-+ semantic_annotations.layout(&layout);
-+ }
-
- if ctx.options().rust_features().repr_align {
- if let Some(explicit) = explicit_align {
-@@ -2225,6 +2296,16 @@ impl CodeGenerator for CompInfo {
- attributes.push(attributes::derives(&derives))
- }
-
-+ if let Some(original_name) = item.original_name(ctx) {
-+ if canonical_name != original_name {
-+ let mut semantic_annotations = CppSemanticAttributeAdder::new(
-+ ctx.options(),
-+ &mut attributes,
-+ );
-+ semantic_annotations.original_name(&original_name);
-+ }
-+ }
-+
- if item.must_use(ctx) {
- attributes.push(attributes::must_use());
- }
-@@ -2604,8 +2685,9 @@ impl Method {
- write!(&mut function_name, "{}", times_seen).unwrap();
- }
- let function_name = ctx.rust_ident(function_name);
-- let mut args = utils::fnsig_arguments(ctx, signature);
-- let mut ret = utils::fnsig_return_ty(ctx, signature);
-+ let (mut args, args_attributes) =
-+ utils::fnsig_arguments(ctx, signature);
-+ let (mut ret, ret_attr) = utils::fnsig_return_ty(ctx, signature);
-
- if !self.is_static() && !self.is_constructor() {
- args[0] = if self.is_const() {
-@@ -2681,7 +2763,9 @@ impl Method {
-
- let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*));
-
-- let mut attrs = vec![attributes::inline()];
-+ let mut attrs = args_attributes;
-+ attrs.push(ret_attr);
-+ attrs.push(attributes::inline());
-
- if signature.must_use() &&
- ctx.options().rust_features().must_use_function
-@@ -3202,6 +3286,15 @@ impl CodeGenerator for Enum {
-
- let mut attrs = vec![];
-
-+ let mut semantic_annotations =
-+ CppSemanticAttributeAdder::new(ctx.options(), &mut attrs);
-+ if let Some(original_name) = item.original_name(ctx) {
-+ if name != original_name {
-+ semantic_annotations.original_name(&original_name);
-+ }
-+ }
-+ semantic_annotations.visibility(self.visibility);
-+
- // TODO(emilio): Delegate this to the builders?
- match variation {
- EnumVariation::Rust { non_exhaustive } => {
-@@ -3296,7 +3389,7 @@ impl CodeGenerator for Enum {
- });
- }
-
-- let repr = repr.to_rust_ty_or_opaque(ctx, item);
-+ let repr = repr.to_rust_ty_or_opaque(ctx, item).ignore_annotations();
- let has_typedef = ctx.is_enum_typedef_combo(item.id());
-
- let mut builder =
-@@ -3304,7 +3397,8 @@ impl CodeGenerator for Enum {
-
- // A map where we keep a value -> variant relation.
- let mut seen_values = HashMap::<_, Ident>::default();
-- let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &());
-+ let enum_rust_ty =
-+ item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations();
- let is_toplevel = item.is_toplevel(ctx);
-
- // Used to mangle the constants we generate in the unnamed-enum case.
-@@ -3606,9 +3700,9 @@ trait TryToOpaque {
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- self.try_get_layout(ctx, extra)
-- .map(|layout| helpers::blob(ctx, layout))
-+ .map(|layout| helpers::blob(ctx, layout).into())
- }
- }
-
-@@ -3654,7 +3748,7 @@ trait TryToRustTy {
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
-- ) -> error::Result<proc_macro2::TokenStream>;
-+ ) -> error::Result<RustTy>;
- }
-
- /// Fallible conversion to a Rust type or an opaque blob with the correct size
-@@ -3669,7 +3763,7 @@ trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque {
- &self,
- ctx: &BindgenContext,
- extra: &<Self as TryToRustTyOrOpaque>::Extra,
-- ) -> error::Result<proc_macro2::TokenStream>;
-+ ) -> error::Result<RustTy>;
- }
-
- impl<E, T> TryToRustTyOrOpaque for T
-@@ -3682,10 +3776,10 @@ where
- &self,
- ctx: &BindgenContext,
- extra: &E,
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- self.try_to_rust_ty(ctx, extra).or_else(|_| {
- if let Ok(layout) = self.try_get_layout(ctx, extra) {
-- Ok(helpers::blob(ctx, layout))
-+ Ok(helpers::blob(ctx, layout).into())
- } else {
- Err(error::Error::NoLayoutForOpaqueBlob)
- }
-@@ -3717,7 +3811,7 @@ trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
- &self,
- ctx: &BindgenContext,
- extra: &<Self as ToRustTyOrOpaque>::Extra,
-- ) -> proc_macro2::TokenStream;
-+ ) -> RustTy;
- }
-
- impl<E, T> ToRustTyOrOpaque for T
-@@ -3726,13 +3820,9 @@ where
- {
- type Extra = E;
-
-- fn to_rust_ty_or_opaque(
-- &self,
-- ctx: &BindgenContext,
-- extra: &E,
-- ) -> proc_macro2::TokenStream {
-+ fn to_rust_ty_or_opaque(&self, ctx: &BindgenContext, extra: &E) -> RustTy {
- self.try_to_rust_ty(ctx, extra)
-- .unwrap_or_else(|_| self.to_opaque(ctx, extra))
-+ .unwrap_or_else(|_| RustTy::new_opaque(self.to_opaque(ctx, extra)))
- }
- }
-
-@@ -3761,7 +3851,7 @@ where
- &self,
- ctx: &BindgenContext,
- _: &(),
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &())
- }
- }
-@@ -3785,7 +3875,7 @@ impl TryToRustTy for Item {
- &self,
- ctx: &BindgenContext,
- _: &(),
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- self.kind().expect_type().try_to_rust_ty(ctx, self)
- }
- }
-@@ -3802,6 +3892,111 @@ impl TryToOpaque for Type {
- }
- }
-
-+enum RustTyAnnotation {
-+ None,
-+ Reference,
-+ RValueReference,
-+ HasUnusedTemplateArgs,
-+ Opaque,
-+}
-+
-+struct RustTy {
-+ ts: proc_macro2::TokenStream,
-+ annotation: RustTyAnnotation,
-+}
-+
-+impl From<proc_macro2::TokenStream> for RustTy {
-+ fn from(ts: proc_macro2::TokenStream) -> Self {
-+ RustTy::new(ts)
-+ }
-+}
-+
-+impl RustTy {
-+ fn new(ts: proc_macro2::TokenStream) -> Self {
-+ Self {
-+ ts,
-+ annotation: RustTyAnnotation::None,
-+ }
-+ }
-+
-+ fn new_opaque(ts: proc_macro2::TokenStream) -> Self {
-+ Self {
-+ ts,
-+ annotation: RustTyAnnotation::Opaque,
-+ }
-+ }
-+
-+ fn new_reference(
-+ ts: proc_macro2::TokenStream,
-+ inner: RustTyAnnotation,
-+ ) -> Self {
-+ let annotation = match inner {
-+ RustTyAnnotation::HasUnusedTemplateArgs |
-+ RustTyAnnotation::Opaque => inner,
-+ _ => RustTyAnnotation::Reference,
-+ };
-+ Self { ts, annotation }
-+ }
-+
-+ fn new_rvalue_reference(
-+ ts: proc_macro2::TokenStream,
-+ inner: RustTyAnnotation,
-+ ) -> Self {
-+ let annotation = match inner {
-+ RustTyAnnotation::HasUnusedTemplateArgs |
-+ RustTyAnnotation::Opaque => inner,
-+ _ => RustTyAnnotation::RValueReference,
-+ };
-+ Self { ts, annotation }
-+ }
-+
-+ // We're constructing some outer type composed of an inner type,
-+ // e.g. a reference to a T - the inner type is T
-+ fn wraps(ts: proc_macro2::TokenStream, inner: RustTyAnnotation) -> Self {
-+ let annotation = match inner {
-+ RustTyAnnotation::HasUnusedTemplateArgs => {
-+ RustTyAnnotation::HasUnusedTemplateArgs
-+ }
-+ _ => RustTyAnnotation::None,
-+ };
-+ Self { ts, annotation }
-+ }
-+
-+ fn with_unused_template_args(
-+ ts: proc_macro2::TokenStream,
-+ has_unused_args: bool,
-+ ) -> Self {
-+ Self {
-+ ts,
-+ annotation: if has_unused_args {
-+ RustTyAnnotation::HasUnusedTemplateArgs
-+ } else {
-+ RustTyAnnotation::None
-+ },
-+ }
-+ }
-+
-+ // Where this is called, we're discarding information about whether
-+ // a type is a reference or a pointer. This is not desirable.
-+ fn ignore_annotations(self) -> proc_macro2::TokenStream {
-+ self.ts
-+ }
-+
-+ // Use when this is an inner type and will become part of an outer type.
-+ // Pass the annotation into [wraps]
-+ fn into_outer_type(self) -> (proc_macro2::TokenStream, RustTyAnnotation) {
-+ (self.ts, self.annotation)
-+ }
-+
-+ fn into_unannotated_ts(self) -> error::Result<proc_macro2::TokenStream> {
-+ if matches!(self.annotation, RustTyAnnotation::None) {
-+ Ok(self.ts)
-+ } else {
-+ Err(error::Error::ReferenceButCouldNotRecord)
-+ }
-+ }
-+}
-+
- impl TryToRustTy for Type {
- type Extra = Item;
-
-@@ -3809,28 +4004,30 @@ impl TryToRustTy for Type {
- &self,
- ctx: &BindgenContext,
- item: &Item,
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- use self::helpers::ast_ty::*;
-
- match *self.kind() {
-- TypeKind::Void => Ok(c_void(ctx)),
-+ TypeKind::Void => Ok(c_void(ctx).into()),
- // TODO: we should do something smart with nullptr, or maybe *const
- // c_void is enough?
-- TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)),
-+ TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true).into()),
- TypeKind::Int(ik) => {
- match ik {
-- IntKind::Bool => Ok(quote! { bool }),
-- IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")),
-- IntKind::SChar => Ok(raw_type(ctx, "c_schar")),
-- IntKind::UChar => Ok(raw_type(ctx, "c_uchar")),
-- IntKind::Short => Ok(raw_type(ctx, "c_short")),
-- IntKind::UShort => Ok(raw_type(ctx, "c_ushort")),
-- IntKind::Int => Ok(raw_type(ctx, "c_int")),
-- IntKind::UInt => Ok(raw_type(ctx, "c_uint")),
-- IntKind::Long => Ok(raw_type(ctx, "c_long")),
-- IntKind::ULong => Ok(raw_type(ctx, "c_ulong")),
-- IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")),
-- IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")),
-+ IntKind::Bool => Ok(quote! { bool }.into()),
-+ IntKind::Char { .. } => Ok(raw_type(ctx, "c_char").into()),
-+ IntKind::SChar => Ok(raw_type(ctx, "c_schar").into()),
-+ IntKind::UChar => Ok(raw_type(ctx, "c_uchar").into()),
-+ IntKind::Short => Ok(raw_type(ctx, "c_short").into()),
-+ IntKind::UShort => Ok(raw_type(ctx, "c_ushort").into()),
-+ IntKind::Int => Ok(raw_type(ctx, "c_int").into()),
-+ IntKind::UInt => Ok(raw_type(ctx, "c_uint").into()),
-+ IntKind::Long => Ok(raw_type(ctx, "c_long").into()),
-+ IntKind::ULong => Ok(raw_type(ctx, "c_ulong").into()),
-+ IntKind::LongLong => Ok(raw_type(ctx, "c_longlong").into()),
-+ IntKind::ULongLong => {
-+ Ok(raw_type(ctx, "c_ulonglong").into())
-+ }
- IntKind::WChar => {
- let layout = self
- .layout(ctx)
-@@ -3838,19 +4035,22 @@ impl TryToRustTy for Type {
- let ty = Layout::known_type_for_size(ctx, layout.size)
- .expect("Non-representable wchar_t?");
- let ident = ctx.rust_ident_raw(ty);
-- Ok(quote! { #ident })
-+ Ok(quote! { #ident }.into())
- }
-
-- IntKind::I8 => Ok(quote! { i8 }),
-- IntKind::U8 => Ok(quote! { u8 }),
-- IntKind::I16 => Ok(quote! { i16 }),
-- IntKind::U16 => Ok(quote! { u16 }),
-- IntKind::I32 => Ok(quote! { i32 }),
-- IntKind::U32 => Ok(quote! { u32 }),
-- IntKind::I64 => Ok(quote! { i64 }),
-- IntKind::U64 => Ok(quote! { u64 }),
-+ IntKind::I8 => Ok(quote! { i8 }.into()),
-+ IntKind::U8 => Ok(quote! { u8 }.into()),
-+ IntKind::I16 => Ok(quote! { i16 }.into()),
-+ IntKind::Char16 => Ok(quote! { c_char16_t }.into()),
-+ IntKind::U16 => Ok(quote! { u16 }.into()),
-+ IntKind::I32 => Ok(quote! { i32 }.into()),
-+ IntKind::U32 => Ok(quote! { u32 }.into()),
-+ IntKind::I64 => Ok(quote! { i64 }.into()),
-+ IntKind::U64 => Ok(quote! { u64 }.into()),
- IntKind::Custom { name, .. } => {
-- Ok(proc_macro2::TokenStream::from_str(name).unwrap())
-+ Ok(proc_macro2::TokenStream::from_str(name)
-+ .unwrap()
-+ .into())
- }
- IntKind::U128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
-@@ -3859,19 +4059,21 @@ impl TryToRustTy for Type {
- // Best effort thing, but wrong alignment
- // unfortunately.
- quote! { [u64; 2] }
-- })
-+ }
-+ .into())
- }
- IntKind::I128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
- quote! { i128 }
- } else {
- quote! { [u64; 2] }
-- })
-+ }
-+ .into())
- }
- }
- }
- TypeKind::Float(fk) => {
-- Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)))
-+ Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)).into())
- }
- TypeKind::Complex(fk) => {
- let float_path =
-@@ -3886,31 +4088,35 @@ impl TryToRustTy for Type {
- quote! {
- __BindgenComplex<#float_path>
- }
-- })
-+ }
-+ .into())
- }
- TypeKind::Function(ref fs) => {
- // We can't rely on the sizeof(Option<NonZero<_>>) ==
- // sizeof(NonZero<_>) optimization with opaque blobs (because
- // they aren't NonZero), so don't *ever* use an or_opaque
- // variant here.
-- let ty = fs.try_to_rust_ty(ctx, &())?;
-+ let ty = fs.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
-
- let prefix = ctx.trait_prefix();
- Ok(quote! {
- ::#prefix::option::Option<#ty>
-- })
-+ }
-+ .into())
- }
- TypeKind::Array(item, len) | TypeKind::Vector(item, len) => {
-- let ty = item.try_to_rust_ty(ctx, &())?;
-+ let ty =
-+ item.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
- Ok(quote! {
- [ #ty ; #len ]
-- })
-+ }
-+ .into())
- }
- TypeKind::Enum(..) => {
- let path = item.namespace_aware_canonical_path(ctx);
- let path = proc_macro2::TokenStream::from_str(&path.join("::"))
- .unwrap();
-- Ok(quote!(#path))
-+ Ok(quote!(#path).into())
- }
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.try_to_rust_ty(ctx, item)
-@@ -3921,22 +4127,22 @@ impl TryToRustTy for Type {
- TypeKind::BlockPointer(..) => {
- if self.is_block_pointer() && !ctx.options().generate_block {
- let void = c_void(ctx);
-- return Ok(void.to_ptr(/* is_const = */ false));
-+ return Ok(void.to_ptr(/* is_const = */ false).into());
- }
-
-- if item.is_opaque(ctx, &()) &&
-- item.used_template_params(ctx)
-- .into_iter()
-- .any(|param| param.is_template_param(ctx, &()))
-- {
-+ let (used_template_params, _) = item.used_template_params(ctx);
-+ let has_used_template_params = used_template_params
-+ .into_iter()
-+ .any(|param| param.is_template_param(ctx, &()));
-+ if item.is_opaque(ctx, &()) && has_used_template_params {
- self.try_to_opaque(ctx, item)
- } else if let Some(ty) = self
- .name()
- .and_then(|name| utils::type_from_named(ctx, name))
- {
-- Ok(ty)
-+ Ok(ty.into())
- } else {
-- utils::build_path(item, ctx)
-+ Ok(utils::build_path(item, ctx)?.into())
- }
- }
- TypeKind::Comp(ref info) => {
-@@ -3947,11 +4153,15 @@ impl TryToRustTy for Type {
- return self.try_to_opaque(ctx, item);
- }
-
-- utils::build_path(item, ctx)
-+ Ok(utils::build_path(item, ctx)?.into())
- }
- TypeKind::Opaque => self.try_to_opaque(ctx, item),
-- TypeKind::Pointer(inner) | TypeKind::Reference(inner) => {
-+ TypeKind::Pointer(inner) | TypeKind::Reference(inner, _) => {
- let is_const = ctx.resolve_type(inner).is_const();
-+ let is_reference =
-+ matches!(self.kind(), TypeKind::Reference(_, false));
-+ let is_rvalue_reference =
-+ matches!(self.kind(), TypeKind::Reference(_, true));
-
- let inner =
- inner.into_resolver().through_type_refs().resolve(ctx);
-@@ -3963,16 +4173,24 @@ impl TryToRustTy for Type {
- // Regardless if we can properly represent the inner type, we
- // should always generate a proper pointer here, so use
- // infallible conversion of the inner type.
-- let mut ty = inner.to_rust_ty_or_opaque(ctx, &());
-+ let (mut ty, inner_annotations) =
-+ inner.to_rust_ty_or_opaque(ctx, &()).into_outer_type();
- ty.append_implicit_template_params(ctx, inner);
-
- // Avoid the first function pointer level, since it's already
- // represented in Rust.
- if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
- {
-- Ok(ty)
-+ Ok(RustTy::wraps(ty, inner_annotations))
- } else {
-- Ok(ty.to_ptr(is_const))
-+ let ty_ptr = ty.to_ptr(is_const);
-+ Ok(if is_rvalue_reference {
-+ RustTy::new_rvalue_reference(ty_ptr, inner_annotations)
-+ } else if is_reference {
-+ RustTy::new_reference(ty_ptr, inner_annotations)
-+ } else {
-+ RustTy::wraps(ty_ptr, inner_annotations)
-+ })
- }
- }
- TypeKind::TypeParam => {
-@@ -3980,19 +4198,23 @@ impl TryToRustTy for Type {
- let ident = ctx.rust_ident(name);
- Ok(quote! {
- #ident
-- })
-+ }
-+ .into())
- }
- TypeKind::ObjCSel => Ok(quote! {
- objc::runtime::Sel
-- }),
-+ }
-+ .into()),
- TypeKind::ObjCId => Ok(quote! {
- id
-- }),
-+ }
-+ .into()),
- TypeKind::ObjCInterface(ref interface) => {
- let name = ctx.rust_ident(interface.name());
- Ok(quote! {
- #name
-- })
-+ }
-+ .into())
- }
- ref u @ TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("Should have been resolved after parsing {:?}!", u)
-@@ -4022,7 +4244,7 @@ impl TryToRustTy for TemplateInstantiation {
- &self,
- ctx: &BindgenContext,
- item: &Item,
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- if self.is_opaque(ctx, item) {
- return Err(error::Error::InstantiationOfOpaqueType);
- }
-@@ -4066,19 +4288,32 @@ impl TryToRustTy for TemplateInstantiation {
- .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param))
- .map(|(arg, _)| {
- let arg = arg.into_resolver().through_type_refs().resolve(ctx);
-- let mut ty = arg.try_to_rust_ty(ctx, &())?;
-+ let mut ty =
-+ arg.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?;
- ty.append_implicit_template_params(ctx, arg);
- Ok(ty)
- })
- .collect::<error::Result<Vec<_>>>()?;
-
-+ let has_unused_template_args = def_params
-+ .iter()
-+ // Only pass type arguments for the type parameters that
-+ // the def uses.
-+ .any(|param| !ctx.uses_template_parameter(def.id(), *param));
-+
- if template_args.is_empty() {
-- return Ok(ty);
-+ return Ok(RustTy::with_unused_template_args(
-+ ty,
-+ has_unused_template_args,
-+ ));
- }
-
-- Ok(quote! {
-- #ty < #( #template_args ),* >
-- })
-+ Ok(RustTy::with_unused_template_args(
-+ quote! {
-+ #ty < #( #template_args ),* >
-+ },
-+ has_unused_template_args,
-+ ))
- }
- }
-
-@@ -4089,39 +4324,40 @@ impl TryToRustTy for FunctionSig {
- &self,
- ctx: &BindgenContext,
- _: &(),
-- ) -> error::Result<proc_macro2::TokenStream> {
-+ ) -> error::Result<RustTy> {
- // TODO: we might want to consider ignoring the reference return value.
-- let ret = utils::fnsig_return_ty(ctx, self);
-- let arguments = utils::fnsig_arguments(ctx, self);
-+ let (ret, _) = utils::fnsig_return_ty(ctx, self);
-+ let (arguments, _) = utils::fnsig_arguments(ctx, self);
-
- match self.abi(ctx, None) {
- ClangAbi::Known(Abi::ThisCall)
- if !ctx.options().rust_features().thiscall_abi =>
- {
- warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
-- Ok(proc_macro2::TokenStream::new())
-+ Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::Vectorcall)
- if !ctx.options().rust_features().vectorcall_abi =>
- {
- warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
-- Ok(proc_macro2::TokenStream::new())
-+ Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::CUnwind)
- if !ctx.options().rust_features().c_unwind_abi =>
- {
- warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target");
-- Ok(proc_macro2::TokenStream::new())
-+ Ok(proc_macro2::TokenStream::new().into())
- }
- ClangAbi::Known(Abi::EfiApi)
- if !ctx.options().rust_features().abi_efiapi =>
- {
- warn!("Skipping function with efiapi ABI that isn't supported by the configured Rust target");
-- Ok(proc_macro2::TokenStream::new())
-+ Ok(proc_macro2::TokenStream::new().into())
- }
- abi => Ok(quote! {
- unsafe extern #abi fn ( #( #arguments ),* ) #ret
-- }),
-+ }
-+ .into()),
- }
- }
- }
-@@ -4150,14 +4386,19 @@ impl CodeGenerator for Function {
- return None;
- }
-
-- // Pure virtual methods have no actual symbol, so we can't generate
-- // something meaningful for them.
-- let is_dynamic_function = match self.kind() {
-- FunctionKind::Method(ref method_kind)
-- if method_kind.is_pure_virtual() =>
-- {
-- return None;
-+ let is_pure_virtual = match self.kind() {
-+ FunctionKind::Method(ref method_kind) => {
-+ method_kind.is_pure_virtual()
- }
-+ _ => false,
-+ };
-+
-+ let is_virtual = matches!(
-+ self.kind(),
-+ FunctionKind::Method(MethodKind::Virtual { .. })
-+ );
-+
-+ let is_dynamic_function = match self.kind() {
- FunctionKind::Function => {
- ctx.options().dynamic_library_name.is_some()
- }
-@@ -4194,10 +4435,11 @@ impl CodeGenerator for Function {
- _ => panic!("Signature kind is not a Function: {:?}", signature),
- };
-
-- let args = utils::fnsig_arguments(ctx, signature);
-- let ret = utils::fnsig_return_ty(ctx, signature);
-+ let (args, args_attrs) = utils::fnsig_arguments(ctx, signature);
-+ let (ret, ret_attr) = utils::fnsig_return_ty(ctx, signature);
-
-- let mut attributes = vec![];
-+ let mut attributes = args_attrs;
-+ attributes.push(ret_attr);
-
- if ctx.options().rust_features().must_use_function {
- let must_use = signature.must_use() || {
-@@ -4218,6 +4460,19 @@ impl CodeGenerator for Function {
- attributes.push(attributes::doc(comment));
- }
-
-+ let mut semantic_annotations =
-+ CppSemanticAttributeAdder::new(ctx.options(), &mut attributes);
-+
-+ if is_pure_virtual {
-+ semantic_annotations.is_pure_virtual();
-+ }
-+
-+ if is_virtual {
-+ semantic_annotations.is_virtual();
-+ }
-+
-+ semantic_annotations.visibility(self.visibility());
-+
- let abi = match signature.abi(ctx, Some(name)) {
- ClangAbi::Known(Abi::ThisCall)
- if !ctx.options().rust_features().thiscall_abi =>
-@@ -4291,6 +4546,19 @@ impl CodeGenerator for Function {
- if times_seen > 0 {
- write!(&mut canonical_name, "{}", times_seen).unwrap();
- }
-+ if canonical_name != self.name() {
-+ semantic_annotations.original_name(self.name());
-+ }
-+
-+ if let Some(special_member_kind) = self.special_member() {
-+ semantic_annotations.special_member(special_member_kind);
-+ }
-+ if self.deleted_fn() {
-+ semantic_annotations.deleted_fn();
-+ }
-+ if self.defaulted_fn() {
-+ semantic_annotations.defaulted_fn();
-+ }
-
- let mut has_link_name_attr = false;
- if let Some(link_name) = self.link_name() {
-@@ -4345,7 +4613,7 @@ impl CodeGenerator for Function {
- args,
- args_identifiers,
- ret,
-- ret_ty,
-+ ret_ty.0,
- attributes,
- ctx,
- );
-@@ -4418,8 +4686,9 @@ fn objc_method_codegen(
- }
-
- let signature = method.signature();
-- let fn_args = utils::fnsig_arguments(ctx, signature);
-- let fn_ret = utils::fnsig_return_ty(ctx, signature);
-+ let (fn_args, _) = utils::fnsig_arguments(ctx, signature);
-+ let (fn_ret, _) = utils::fnsig_return_ty(ctx, signature);
-+ // We disregard reference vs pointer attributes for objc methods for now.
-
- let sig = if method.is_class_method() {
- quote! {
-@@ -4732,7 +5001,13 @@ pub(crate) fn codegen(
-
- pub(crate) mod utils {
- use super::serialize::CSerialize;
-- use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
-+ use super::{
-+ error, CodegenError, CodegenResult, RustTy, RustTyAnnotation,
-+ ToRustTyOrOpaque,
-+ };
-+ use crate::codegen::helpers::{
-+ CppSemanticAttributeCreator, CppSemanticAttributeSingle,
-+ };
- use crate::ir::context::BindgenContext;
- use crate::ir::function::{Abi, ClangAbi, FunctionSig};
- use crate::ir::item::{Item, ItemCanonicalPath};
-@@ -5128,12 +5403,12 @@ pub(crate) mod utils {
- ctx: &BindgenContext,
- sig: &FunctionSig,
- include_arrow: bool,
-- ) -> proc_macro2::TokenStream {
-+ ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
- if sig.is_divergent() {
- return if include_arrow {
-- quote! { -> ! }
-+ (quote! { -> ! }, quote! {})
- } else {
-- quote! { ! }
-+ (quote! { ! }, quote! {})
- };
- }
-
-@@ -5149,35 +5424,54 @@ pub(crate) mod utils {
-
- if let TypeKind::Void = canonical_type_kind {
- return if include_arrow {
-- quote! {}
-+ (quote! {}, quote! {})
- } else {
-- quote! { () }
-+ (quote! { () }, quote! {})
- };
- }
-
- let ret_ty = sig.return_type().to_rust_ty_or_opaque(ctx, &());
-- if include_arrow {
-+ let annotations = ret_ty.annotation;
-+ let ret_ty = ret_ty.ts;
-+ let ts = if include_arrow {
- quote! { -> #ret_ty }
- } else {
- ret_ty
-- }
-+ };
-+
-+ let mut semantic_annotation =
-+ CppSemanticAttributeSingle::new(ctx.options());
-+ match annotations {
-+ super::RustTyAnnotation::None => {}
-+ super::RustTyAnnotation::Reference => {
-+ semantic_annotation.ret_type_reference()
-+ }
-+ super::RustTyAnnotation::RValueReference => {
-+ semantic_annotation.ret_type_rvalue_reference()
-+ }
-+ super::RustTyAnnotation::HasUnusedTemplateArgs |
-+ super::RustTyAnnotation::Opaque => {
-+ semantic_annotation.incomprehensible_param_in_arg_or_return()
-+ }
-+ };
-+ (ts, semantic_annotation.result())
- }
-
- pub(crate) fn fnsig_return_ty(
- ctx: &BindgenContext,
- sig: &FunctionSig,
-- ) -> proc_macro2::TokenStream {
-+ ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
- fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true)
- }
-
- pub(crate) fn fnsig_arguments(
- ctx: &BindgenContext,
- sig: &FunctionSig,
-- ) -> Vec<proc_macro2::TokenStream> {
-+ ) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) {
- use super::ToPtr;
-
- let mut unnamed_arguments = 0;
-- let mut args = sig
-+ let mut args: (Vec<_>, Vec<_>) = sig
- .argument_types()
- .iter()
- .map(|&(ref name, ty)| {
-@@ -5192,15 +5486,19 @@ pub(crate) mod utils {
- // the array type derivation.
- //
- // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
-- let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
-+ let arg_details = match *arg_ty.canonical_type(ctx).kind() {
- TypeKind::Array(t, _) => {
-- let stream =
-+ let rust_ty =
- if ctx.options().array_pointers_in_arguments {
- arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
- } else {
- t.to_rust_ty_or_opaque(ctx, &())
- };
-- stream.to_ptr(ctx.resolve_type(t).is_const())
-+ let (inner_ty, annotations) = rust_ty.into_outer_type();
-+ RustTy::wraps(
-+ inner_ty.to_ptr(ctx.resolve_type(t).is_const()),
-+ annotations,
-+ )
- }
- TypeKind::Pointer(inner) => {
- let inner = ctx.resolve_item(inner);
-@@ -5209,15 +5507,16 @@ pub(crate) mod utils {
- *inner_ty.canonical_type(ctx).kind()
- {
- let name = ctx.rust_ident(interface.name());
-- quote! {
-+ RustTy::new(quote! {
- #name
-- }
-+ })
- } else {
- arg_item.to_rust_ty_or_opaque(ctx, &())
- }
- }
- _ => arg_item.to_rust_ty_or_opaque(ctx, &()),
- };
-+ let arg_ty = arg_details.ts;
-
- let arg_name = match *name {
- Some(ref name) => ctx.rust_mangle(name).into_owned(),
-@@ -5229,15 +5528,33 @@ pub(crate) mod utils {
-
- assert!(!arg_name.is_empty());
- let arg_name = ctx.rust_ident(arg_name);
-+ let mut semantic_annotation =
-+ CppSemanticAttributeSingle::new(ctx.options());
-+ match arg_details.annotation {
-+ RustTyAnnotation::None => {}
-+ RustTyAnnotation::Reference => {
-+ semantic_annotation.arg_type_reference(&arg_name)
-+ }
-+ RustTyAnnotation::RValueReference => {
-+ semantic_annotation.arg_type_rvalue_reference(&arg_name)
-+ }
-+ RustTyAnnotation::HasUnusedTemplateArgs |
-+ RustTyAnnotation::Opaque => semantic_annotation
-+ .incomprehensible_param_in_arg_or_return(),
-+ };
-
-- quote! {
-- #arg_name : #arg_ty
-- }
-+ (
-+ quote! {
-+ #arg_name : #arg_ty
-+ },
-+ semantic_annotation.result(),
-+ )
- })
-- .collect::<Vec<_>>();
-+ .unzip();
-
- if sig.is_variadic() {
-- args.push(quote! { ... })
-+ args.0.push(quote! { ... });
-+ args.1.push(quote! {});
- }
-
- args
-@@ -5279,12 +5596,13 @@ pub(crate) mod utils {
- let args = sig.argument_types().iter().map(|&(_, ty)| {
- let arg_item = ctx.resolve_item(ty);
-
-- arg_item.to_rust_ty_or_opaque(ctx, &())
-+ arg_item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations()
- });
-
- let ret_ty = fnsig_return_ty_internal(
- ctx, sig, /* include_arrow = */ false,
-- );
-+ )
-+ .0;
- quote! {
- *const ::block::Block<(#(#args,)*), #ret_ty>
- }
-diff --git a/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs
-index 980a551..12b1fe0 100644
---- a/ir/analysis/has_vtable.rs
-+++ b/ir/analysis/has_vtable.rs
-@@ -164,7 +164,7 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::ResolvedTypeRef(t) |
-- TypeKind::Reference(t) => {
-+ TypeKind::Reference(t, _) => {
- trace!(
- " aliases and references forward to their inner type"
- );
-diff --git a/ir/comp.rs b/ir/comp.rs
-index 89e77e1..1ff8961 100644
---- a/ir/comp.rs
-+++ b/ir/comp.rs
-@@ -4,6 +4,7 @@ use super::analysis::Sizedness;
- use super::annotations::Annotations;
- use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
- use super::dot::DotAttributes;
-+use super::function::Visibility;
- use super::item::{IsOpaque, Item};
- use super::layout::Layout;
- use super::template::TemplateParameters;
-@@ -72,6 +73,18 @@ impl MethodKind {
- }
- }
-
-+// The kind of C++ special member.
-+// TODO: We don't currently cover copy assignment or move assignment operator
-+// because libclang doesn't provide a way to query for them.
-+#[derive(Debug, Copy, Clone, PartialEq)]
-+pub enum SpecialMemberKind {
-+ DefaultConstructor,
-+ CopyConstructor,
-+ MoveConstructor,
-+ Destructor,
-+ AssignmentOperator,
-+}
-+
- /// A struct representing a C++ method, either static, normal, or virtual.
- #[derive(Debug)]
- pub(crate) struct Method {
-@@ -976,6 +989,10 @@ pub(crate) struct CompInfo {
- /// Whether this is a struct or a union.
- kind: CompKind,
-
-+ /// The visibility of this struct or union if it was declared inside of
-+ /// another type. Top-level types always have public visibility.
-+ visibility: Visibility,
-+
- /// The members of this struct or union.
- fields: CompFields,
-
-@@ -1055,6 +1072,7 @@ impl CompInfo {
- pub(crate) fn new(kind: CompKind) -> Self {
- CompInfo {
- kind,
-+ visibility: Visibility::Public,
- fields: CompFields::default(),
- template_params: vec![],
- methods: vec![],
-@@ -1166,6 +1184,11 @@ impl CompInfo {
- }
- }
-
-+ /// Returns the visibility of the type.
-+ pub fn visibility(&self) -> Visibility {
-+ self.visibility
-+ }
-+
- /// Returns whether we have a too large bitfield unit, in which case we may
- /// not be able to derive some of the things we should be able to normally
- /// derive.
-@@ -1255,6 +1278,7 @@ impl CompInfo {
- debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
-
- let mut ci = CompInfo::new(kind);
-+ ci.visibility = Visibility::from(cursor.access_specifier());
- ci.is_forward_declaration =
- location.map_or(true, |cur| match cur.kind() {
- CXCursor_ParmDecl => true,
-diff --git a/ir/context.rs b/ir/context.rs
-index a5c14a8..80e7f8d 100644
---- a/ir/context.rs
-+++ b/ir/context.rs
-@@ -1971,6 +1971,9 @@ If you encounter an error missing from this list, please file an issue or a PR!"
- CXType_Short => TypeKind::Int(IntKind::Short),
- CXType_UShort => TypeKind::Int(IntKind::UShort),
- CXType_WChar => TypeKind::Int(IntKind::WChar),
-+ CXType_Char16 if self.options().use_distinct_char16_t => {
-+ TypeKind::Int(IntKind::Char16)
-+ }
- CXType_Char16 => TypeKind::Int(IntKind::U16),
- CXType_Char32 => TypeKind::Int(IntKind::U32),
- CXType_Long => TypeKind::Int(IntKind::Long),
-diff --git a/ir/enum_ty.rs b/ir/enum_ty.rs
-index 70cf0ea..a863340 100644
---- a/ir/enum_ty.rs
-+++ b/ir/enum_ty.rs
-@@ -2,6 +2,7 @@
-
- use super::super::codegen::EnumVariation;
- use super::context::{BindgenContext, TypeId};
-+use super::function::Visibility;
- use super::item::Item;
- use super::ty::{Type, TypeKind};
- use crate::clang;
-@@ -32,6 +33,10 @@ pub(crate) struct Enum {
-
- /// The different variants, with explicit values.
- variants: Vec<EnumVariant>,
-+
-+ /// The visibility of this enum if it was declared inside of
-+ /// another type. Top-level types always have public visibility.
-+ pub(crate) visibility: Visibility,
- }
-
- impl Enum {
-@@ -39,8 +44,13 @@ impl Enum {
- pub(crate) fn new(
- repr: Option<TypeId>,
- variants: Vec<EnumVariant>,
-+ visibility: Visibility,
- ) -> Self {
-- Enum { repr, variants }
-+ Enum {
-+ repr,
-+ variants,
-+ visibility,
-+ }
- }
-
- /// Get this enumeration's representation.
-@@ -56,6 +66,7 @@ impl Enum {
- /// Construct an enumeration from the given Clang type.
- pub(crate) fn from_ty(
- ty: &clang::Type,
-+ visibility: Visibility,
- ctx: &mut BindgenContext,
- ) -> Result<Self, ParseError> {
- use clang_sys::*;
-@@ -147,7 +158,7 @@ impl Enum {
- }
- CXChildVisit_Continue
- });
-- Ok(Enum::new(repr, variants))
-+ Ok(Enum::new(repr, variants, visibility))
- }
-
- fn is_matching_enum(
-diff --git a/ir/function.rs b/ir/function.rs
-index fab380e..d38c60e 100644
---- a/ir/function.rs
-+++ b/ir/function.rs
-@@ -1,6 +1,6 @@
- //! Intermediate representation for C/C++ functions and methods.
-
--use super::comp::MethodKind;
-+use super::comp::{MethodKind, SpecialMemberKind};
- use super::context::{BindgenContext, TypeId};
- use super::dot::DotAttributes;
- use super::item::Item;
-@@ -9,7 +9,9 @@ use super::ty::TypeKind;
- use crate::callbacks::{ItemInfo, ItemKind};
- use crate::clang::{self, Attribute};
- use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
--use clang_sys::{self, CXCallingConv};
-+use clang_sys::{
-+ self, CXCallingConv, CX_CXXAccessSpecifier, CX_CXXPrivate, CX_CXXProtected,
-+};
-
- use quote::TokenStreamExt;
- use std::io;
-@@ -70,6 +72,75 @@ pub(crate) enum Linkage {
- Internal,
- }
-
-+/// Visibility
-+#[derive(Debug, Clone, Copy)]
-+pub enum Visibility {
-+ Public,
-+ Protected,
-+ Private,
-+}
-+
-+impl From<CX_CXXAccessSpecifier> for Visibility {
-+ fn from(access_specifier: CX_CXXAccessSpecifier) -> Self {
-+ if access_specifier == CX_CXXPrivate {
-+ Visibility::Private
-+ } else if access_specifier == CX_CXXProtected {
-+ Visibility::Protected
-+ } else {
-+ Visibility::Public
-+ }
-+ }
-+}
-+
-+/// Autocxx specialized function information
-+#[derive(Debug)]
-+pub(crate) struct AutocxxFuncInfo {
-+ /// C++ Special member kind, if applicable
-+ special_member: Option<SpecialMemberKind>,
-+ /// Whether it is private
-+ visibility: Visibility,
-+ /// =delete
-+ is_deleted: bool,
-+ /// =default
-+ is_defaulted: bool,
-+}
-+
-+impl AutocxxFuncInfo {
-+ fn new(
-+ special_member: Option<SpecialMemberKind>,
-+ visibility: Visibility,
-+ is_deleted: bool,
-+ is_defaulted: bool,
-+ ) -> Self {
-+ Self {
-+ special_member,
-+ visibility,
-+ is_deleted,
-+ is_defaulted,
-+ }
-+ }
-+
-+ /// Get this function's C++ special member kind.
-+ pub fn special_member(&self) -> Option<SpecialMemberKind> {
-+ self.special_member
-+ }
-+
-+ /// Whether it is private
-+ pub fn visibility(&self) -> Visibility {
-+ self.visibility
-+ }
-+
-+ /// Whether this is a function that's been deleted (=delete)
-+ pub fn deleted_fn(&self) -> bool {
-+ self.is_deleted
-+ }
-+
-+ /// Whether this is a function that's been deleted (=default)
-+ pub fn defaulted_fn(&self) -> bool {
-+ self.is_defaulted
-+ }
-+}
-+
- /// A function declaration, with a signature, arguments, and argument names.
- ///
- /// The argument names vector must be the same length as the ones in the
-@@ -93,6 +164,9 @@ pub(crate) struct Function {
-
- /// The linkage of the function.
- linkage: Linkage,
-+
-+ /// Autocxx extension information
-+ autocxx: AutocxxFuncInfo,
- }
-
- impl Function {
-@@ -104,6 +178,7 @@ impl Function {
- signature: TypeId,
- kind: FunctionKind,
- linkage: Linkage,
-+ autocxx: AutocxxFuncInfo,
- ) -> Self {
- Function {
- name,
-@@ -112,6 +187,7 @@ impl Function {
- signature,
- kind,
- linkage,
-+ autocxx,
- }
- }
-
-@@ -144,6 +220,26 @@ impl Function {
- pub(crate) fn linkage(&self) -> Linkage {
- self.linkage
- }
-+
-+ /// Get this function's C++ special member kind.
-+ pub fn special_member(&self) -> Option<SpecialMemberKind> {
-+ self.autocxx.special_member()
-+ }
-+
-+ /// Whether it is private
-+ pub fn visibility(&self) -> Visibility {
-+ self.autocxx.visibility()
-+ }
-+
-+ /// Whether this is a function that's been deleted (=delete)
-+ pub fn deleted_fn(&self) -> bool {
-+ self.autocxx.deleted_fn()
-+ }
-+
-+ /// Whether this is a function that's been deleted (=default)
-+ pub fn defaulted_fn(&self) -> bool {
-+ self.autocxx.defaulted_fn()
-+ }
- }
-
- impl DotAttributes for Function {
-@@ -422,15 +518,6 @@ impl FunctionSig {
-
- let spelling = cursor.spelling();
-
-- // Don't parse operatorxx functions in C++
-- let is_operator = |spelling: &str| {
-- spelling.starts_with("operator") &&
-- !clang::is_valid_identifier(spelling)
-- };
-- if is_operator(&spelling) {
-- return Err(ParseError::Continue);
-- }
--
- // Constructors of non-type template parameter classes for some reason
- // include the template parameter in their name. Just skip them, since
- // we don't handle well non-type template parameters anyway.
-@@ -513,7 +600,10 @@ impl FunctionSig {
- let is_const = is_method && cursor.method_is_const();
- let is_virtual = is_method && cursor.method_is_virtual();
- let is_static = is_method && cursor.method_is_static();
-- if !is_static && !is_virtual {
-+ if !is_static &&
-+ (!is_virtual ||
-+ ctx.options().use_specific_virtual_function_receiver)
-+ {
- let parent = cursor.semantic_parent();
- let class = Item::parse(parent, None, ctx)
- .expect("Expected to parse the class");
-@@ -537,7 +627,7 @@ impl FunctionSig {
- Item::builtin_type(TypeKind::Pointer(class), false, ctx);
- args.insert(0, (Some("this".into()), ptr));
- } else if is_virtual {
-- let void = Item::builtin_type(TypeKind::Void, false, ctx);
-+ let void = Item::builtin_type(TypeKind::Void, is_const, ctx);
- let ptr =
- Item::builtin_type(TypeKind::Pointer(void), false, ctx);
- args.insert(0, (Some("this".into()), ptr));
-@@ -685,9 +775,7 @@ impl ClangSubItemParser for Function {
- return Err(ParseError::Continue);
- }
-
-- if cursor.access_specifier() == CX_CXXPrivate {
-- return Err(ParseError::Continue);
-- }
-+ let visibility = Visibility::from(cursor.access_specifier());
-
- let linkage = cursor.linkage();
- let linkage = match linkage {
-@@ -707,10 +795,6 @@ impl ClangSubItemParser for Function {
- return Err(ParseError::Continue);
- }
-
-- if cursor.is_deleted_function() {
-- return Err(ParseError::Continue);
-- }
--
- // We cannot handle `inline` functions that are not `static`.
- if context.options().wrap_static_fns &&
- cursor.is_inlined_function() &&
-@@ -749,7 +833,23 @@ impl ClangSubItemParser for Function {
- }
- assert!(!name.is_empty(), "Empty function name.");
-
-- let mangled_name = cursor_mangling(context, &cursor);
-+ let operator_suffix = name.strip_prefix("operator");
-+ let special_member = if let Some(operator_suffix) = operator_suffix {
-+ // We can't represent operatorxx functions as-is because
-+ // they are not valid identifiers
-+ if context.options().represent_cxx_operators {
-+ let (new_suffix, special_member) = match operator_suffix {
-+ "=" => ("equals", SpecialMemberKind::AssignmentOperator),
-+ _ => return Err(ParseError::Continue),
-+ };
-+ name = format!("operator_{}", new_suffix);
-+ Some(special_member)
-+ } else {
-+ return Err(ParseError::Continue);
-+ }
-+ } else {
-+ None
-+ };
-
- let link_name = context.options().last_callback(|callbacks| {
- callbacks.generated_link_name_override(ItemInfo {
-@@ -758,13 +858,36 @@ impl ClangSubItemParser for Function {
- })
- });
-
-+ let mangled_name = cursor_mangling(context, &cursor);
-+
-+ let special_member = special_member.or_else(|| {
-+ if cursor.is_default_constructor() {
-+ Some(SpecialMemberKind::DefaultConstructor)
-+ } else if cursor.is_copy_constructor() {
-+ Some(SpecialMemberKind::CopyConstructor)
-+ } else if cursor.is_move_constructor() {
-+ Some(SpecialMemberKind::MoveConstructor)
-+ } else if cursor.kind() == clang_sys::CXCursor_Destructor {
-+ Some(SpecialMemberKind::Destructor)
-+ } else {
-+ None
-+ }
-+ });
-+
-+ let autocxx_info = AutocxxFuncInfo::new(
-+ special_member,
-+ visibility,
-+ cursor.is_deleted_function(),
-+ cursor.is_defaulted_function(),
-+ );
- let function = Self::new(
-- name.clone(),
-+ name,
- mangled_name,
- link_name,
- sig,
- kind,
- linkage,
-+ autocxx_info,
- );
-
- Ok(ParseResult::New(function, Some(cursor)))
-diff --git a/ir/int.rs b/ir/int.rs
-index 4251b37..ea2456e 100644
---- a/ir/int.rs
-+++ b/ir/int.rs
-@@ -54,9 +54,12 @@ pub enum IntKind {
- /// A 16-bit signed integer.
- I16,
-
-- /// Either a `char16_t` or a `wchar_t`.
-+ /// A 16-bit integer, used only for enum size representation.
- U16,
-
-+ /// Either a `char16_t` or a `wchar_t`.
-+ Char16,
-+
- /// A 32-bit signed integer.
- I32,
-
-@@ -94,7 +97,7 @@ impl IntKind {
- // to know whether it is or not right now (unlike char, there's no
- // WChar_S / WChar_U).
- Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
-- WChar | U32 | U64 | U128 => false,
-+ Char16 | WChar | U32 | U64 | U128 => false,
-
- SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
- I128 => true,
-@@ -112,7 +115,7 @@ impl IntKind {
- use self::IntKind::*;
- Some(match *self {
- Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
-- U16 | I16 => 2,
-+ U16 | I16 | Char16 => 2,
- U32 | I32 => 4,
- U64 | I64 => 8,
- I128 | U128 => 16,
-diff --git a/ir/item.rs b/ir/item.rs
-index a50d267..c35b2ac 100644
---- a/ir/item.rs
-+++ b/ir/item.rs
-@@ -823,6 +823,38 @@ impl Item {
- }
- }
-
-+ /// Get this item's original C++ name, including any containing types, but without
-+ /// the namespace name. For nested types, the C++ name differs from the Rust name, e.g.
-+ /// a nested C++ type `A::B` would correspond to the Rust type `A_B`.
-+ /// If the item or any of its containing types is anonymous, returns None.
-+ pub fn original_name(&self, ctx: &BindgenContext) -> Option<String> {
-+ let target = ctx.resolve_item(self.name_target(ctx));
-+
-+ // Get item and all ancestors until the first enclosing namespace.
-+ let ancestors: Vec<_> = target
-+ .ancestors(ctx)
-+ .map(|id| ctx.resolve_item(id))
-+ .take_while(|item| !item.is_module())
-+ .collect();
-+
-+ if ancestors.iter().any(|item| item.is_anon()) {
-+ return None;
-+ }
-+
-+ let mut names: Vec<_> = ancestors
-+ .iter()
-+ .map(|item| {
-+ let target = ctx.resolve_item(item.name_target(ctx));
-+ target.base_name(ctx)
-+ })
-+ .filter(|name| !name.is_empty())
-+ .collect();
-+
-+ names.reverse();
-+
-+ Some(names.join("::"))
-+ }
-+
- /// Get the canonical name without taking into account the replaces
- /// annotation.
- ///
-diff --git a/ir/layout.rs b/ir/layout.rs
-index ba944b0..17ca66e 100644
---- a/ir/layout.rs
-+++ b/ir/layout.rs
-@@ -8,13 +8,13 @@ use std::cmp;
-
- /// A type that represents the struct layout of a type.
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
--pub(crate) struct Layout {
-+pub struct Layout {
- /// The size (in bytes) of this layout.
-- pub(crate) size: usize,
-+ pub size: usize,
- /// The alignment (in bytes) of this layout.
-- pub(crate) align: usize,
-+ pub align: usize,
- /// Whether this layout's members are packed or not.
-- pub(crate) packed: bool,
-+ pub packed: bool,
- }
-
- #[test]
-diff --git a/ir/template.rs b/ir/template.rs
-index 4dd8442..a1f8f5f 100644
---- a/ir/template.rs
-+++ b/ir/template.rs
-@@ -31,6 +31,7 @@ use super::context::{BindgenContext, ItemId, TypeId};
- use super::item::{IsOpaque, Item, ItemAncestors};
- use super::traversal::{EdgeKind, Trace, Tracer};
- use crate::clang;
-+use itertools::{Either, Itertools};
-
- /// Template declaration (and such declaration's template parameters) related
- /// methods.
-@@ -143,8 +144,9 @@ pub(crate) trait TemplateParameters: Sized {
-
- /// Get only the set of template parameters that this item uses. This is a
- /// subset of `all_template_params` and does not necessarily contain any of
-- /// `self_template_params`.
-- fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
-+ /// `self_template_params`. If any are unused, true will be returned
-+ /// in the second tuple element
-+ fn used_template_params(&self, ctx: &BindgenContext) -> (Vec<TypeId>, bool)
- where
- Self: AsRef<ItemId>,
- {
-@@ -154,11 +156,18 @@ pub(crate) trait TemplateParameters: Sized {
- );
-
- let id = *self.as_ref();
-- ctx.resolve_item(id)
-+ let (used, unused): (Vec<_>, Vec<_>) = ctx
-+ .resolve_item(id)
- .all_template_params(ctx)
- .into_iter()
-- .filter(|p| ctx.uses_template_parameter(id, *p))
-- .collect()
-+ .partition_map(|p| {
-+ if ctx.uses_template_parameter(id, p) {
-+ Either::Left(p)
-+ } else {
-+ Either::Right(true)
-+ }
-+ });
-+ (used, !unused.is_empty())
- }
- }
-
-diff --git a/ir/ty.rs b/ir/ty.rs
-index 8c505aa..5bf3841 100644
---- a/ir/ty.rs
-+++ b/ir/ty.rs
-@@ -14,6 +14,7 @@ use super::template::{
- };
- use super::traversal::{EdgeKind, Trace, Tracer};
- use crate::clang::{self, Cursor};
-+use crate::ir::function::Visibility;
- use crate::parse::{ParseError, ParseResult};
- use std::borrow::Cow;
- use std::io;
-@@ -253,7 +254,9 @@ impl Type {
- ) -> Option<Cow<'a, str>> {
- let name_info = match *self.kind() {
- TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))),
-- TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))),
-+ TypeKind::Reference(inner, _) => {
-+ Some((inner, Cow::Borrowed("ref")))
-+ }
- TypeKind::Array(inner, length) => {
- Some((inner, format!("array{}", length).into()))
- }
-@@ -538,7 +541,7 @@ impl TemplateParameters for TypeKind {
- TypeKind::Enum(_) |
- TypeKind::Pointer(_) |
- TypeKind::BlockPointer(_) |
-- TypeKind::Reference(_) |
-+ TypeKind::Reference(..) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::TypeParam |
- TypeKind::Alias(_) |
-@@ -616,7 +619,8 @@ pub(crate) enum TypeKind {
- BlockPointer(TypeId),
-
- /// A reference to a type, as in: int& foo().
-- Reference(TypeId),
-+ /// The bool represents whether it's rvalue.
-+ Reference(TypeId, bool),
-
- /// An instantiation of an abstract template definition with a set of
- /// concrete template arguments.
-@@ -1044,14 +1048,23 @@ impl Type {
- }
- // XXX: RValueReference is most likely wrong, but I don't think we
- // can even add bindings for that, so huh.
-- CXType_RValueReference | CXType_LValueReference => {
-+ CXType_LValueReference => {
-+ let inner = Item::from_ty_or_ref(
-+ ty.pointee_type().unwrap(),
-+ location,
-+ None,
-+ ctx,
-+ );
-+ TypeKind::Reference(inner, false)
-+ }
-+ CXType_RValueReference => {
- let inner = Item::from_ty_or_ref(
- ty.pointee_type().unwrap(),
- location,
- None,
- ctx,
- );
-- TypeKind::Reference(inner)
-+ TypeKind::Reference(inner, true)
- }
- // XXX DependentSizedArray is wrong
- CXType_VariableArray | CXType_DependentSizedArray => {
-@@ -1109,7 +1122,10 @@ impl Type {
- }
- }
- CXType_Enum => {
-- let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
-+ let visibility =
-+ Visibility::from(cursor.access_specifier());
-+ let enum_ = Enum::from_ty(ty, visibility, ctx)
-+ .expect("Not an enum?");
-
- if !is_anonymous {
- let pretty_name = ty.spelling();
-@@ -1222,7 +1238,7 @@ impl Trace for Type {
- }
- match *self.kind() {
- TypeKind::Pointer(inner) |
-- TypeKind::Reference(inner) |
-+ TypeKind::Reference(inner, _) |
- TypeKind::Array(inner, _) |
- TypeKind::Vector(inner, _) |
- TypeKind::BlockPointer(inner) |
-diff --git a/lib.rs b/lib.rs
-index 482c1a3..e800136 100644
---- a/lib.rs
-+++ b/lib.rs
-@@ -1,5 +1,7 @@
- //! Generate Rust bindings for C and C++ libraries.
- //!
-+//! This is a slightly forked version for use by `autocxx`.
-+//!
- //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
- //! functions and use types defined in the header.
- //!
-@@ -1211,6 +1213,7 @@ fn get_target_dependent_env_var(
- /// When running inside a `build.rs` script, this can be used to make cargo invalidate the
- /// generated bindings whenever any of the files included from the header change:
- /// ```
-+/// use autocxx_bindgen as bindgen;
- /// use bindgen::builder;
- /// let bindings = builder()
- /// .header("path/to/input/header")
-diff --git a/options/mod.rs b/options/mod.rs
-index c60da71..54b44eb 100644
---- a/options/mod.rs
-+++ b/options/mod.rs
-@@ -153,6 +153,61 @@ macro_rules! options {
- }
-
- options! {
-+ /// Whether to specify the type of a virtual function receiver
-+ use_specific_virtual_function_receiver: bool {
-+ methods: {
-+ /// Normally, virtual functions have void* as their 'this' type.
-+ /// If this flag is enabled, override that behavior to indicate a
-+ /// pointer of the specific type.
-+ /// Disabled by default.
-+ pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder {
-+ self.options.use_specific_virtual_function_receiver = doit;
-+ self
-+ }
-+ },
-+ as_args: "--use-specific-virtual-function-receiver",
-+ },
-+
-+ /// Whether we should emit C++ semantics attributes.
-+ cpp_semantic_attributes: bool {
-+ methods: {
-+ /// If this is true, add attributes with details of underlying C++ semantics.
-+ /// Disabled by default.
-+ pub fn cpp_semantic_attributes(mut self, doit: bool) -> Builder {
-+ self.options.cpp_semantic_attributes = doit;
-+ self
-+ }
-+ },
-+ as_args: "--cpp-semantic-attributes",
-+ },
-+
-+ /// Whether we should output information about C++ overloaded operators.
-+ represent_cxx_operators: bool {
-+ methods: {
-+ /// If this is true, output existence of C++ overloaded operators.
-+ /// At present, only operator= is noted.
-+ /// Disabled by default.
-+ pub fn represent_cxx_operators(mut self, doit: bool) -> Builder {
-+ self.options.represent_cxx_operators = doit;
-+ self
-+ }
-+ },
-+ as_args: "--represent-cxx-operators",
-+ },
-+
-+ /// Whether we should distinguish between 'char16_t' and 'u16'
-+ use_distinct_char16_t: bool {
-+ methods: {
-+ /// If this is true, denote 'char16_t' as a separate type from 'u16'
-+ /// Disabled by default.
-+ pub fn use_distinct_char16_t(mut self, doit: bool) -> Builder {
-+ self.options.use_distinct_char16_t = doit;
-+ self
-+ }
-+ },
-+ as_args: "--use-distinct-char16-t",
-+ },
-+
- /// Types that have been blocklisted and should not appear anywhere in the generated code.
- blocklisted_types: RegexSet {
- methods: {
diff --git a/regex_set.rs b/regex_set.rs
index 1d5cad2..b78424a 100644
--- a/regex_set.rs
+++ b/regex_set.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
/// A dynamic set of regular expressions.
#[derive(Clone, Debug, Default)]
pub struct RegexSet {
- items: Vec<String>,
+ items: Vec<Box<str>>,
/// Whether any of the items in the set was ever matched. The length of this
/// vector is exactly the length of `items`.
matched: Vec<Cell<bool>>,
@@ -32,25 +32,25 @@ impl RegexSet {
where
S: AsRef<str>,
{
- self.items.push(string.as_ref().to_owned());
+ self.items.push(string.as_ref().to_owned().into_boxed_str());
self.matched.push(Cell::new(false));
self.set = None;
}
/// Returns slice of String from its field 'items'
- pub fn get_items(&self) -> &[String] {
- &self.items[..]
+ pub fn get_items(&self) -> &[Box<str>] {
+ &self.items
}
/// Returns an iterator over regexes in the set which didn't match any
/// strings yet.
- pub fn unmatched_items(&self) -> impl Iterator<Item = &String> {
+ pub fn unmatched_items(&self) -> impl Iterator<Item = &str> {
self.items.iter().enumerate().filter_map(move |(i, item)| {
if !self.record_matches || self.matched[i].get() {
return None;
}
- Some(item)
+ Some(item.as_ref())
})
}
@@ -197,7 +197,7 @@ fn invalid_regex_warning(
Level::Note,
);
- if set.items.iter().any(|item| item == "*") {
+ if set.items.iter().any(|item| item.as_ref() == "*") {
diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help);
}
diagnostic.display();