diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:11:06 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:11:06 +0000 |
commit | 53b9e0148082702b278396d5b08f6b960ada9bda (patch) | |
tree | c10071f21609dbab1ea57735cf3f4a51e6595bf0 | |
parent | ff539bc03868039787092342a6744b82d7294cd0 (diff) | |
parent | d5f639b2c00c76de49d29c29aa0e78c6387985ba (diff) | |
download | bindgen-android14-qpr2-release.tar.gz |
Snap for 11216811 from d5f639b2c00c76de49d29c29aa0e78c6387985ba to 24Q1-releaseandroid-14.0.0_r37android-14.0.0_r36android-14.0.0_r35android-14.0.0_r34android-14.0.0_r33android-14.0.0_r32android-14.0.0_r31android-14.0.0_r30android-14.0.0_r29android14-qpr2-s5-releaseandroid14-qpr2-s4-releaseandroid14-qpr2-s3-releaseandroid14-qpr2-s2-releaseandroid14-qpr2-s1-releaseandroid14-qpr2-release
Change-Id: Iee30e999d28391ef559446fc2526f829e2f5c23e
38 files changed, 1817 insertions, 4095 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 @@ -1,4 +1,4 @@ -// This file is generated by cargo2android.py --config cargo2android.json. +// This file is generated by cargo_embargo. // Do not modify this file as changes will be overridden on upgrade. package { @@ -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, } @@ -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}})" @@ -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/cargo2android.json b/cargo2android.json deleted file mode 100644 index ea1fdc2..0000000 --- a/cargo2android.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "copy-out": true, - "features": "__cli,experimental,runtime,which-rustfmt", - "host-first-multilib": true, - "run": true -} diff --git a/cargo_embargo.json b/cargo_embargo.json new file mode 100644 index 0000000..3ffb84d --- /dev/null +++ b/cargo_embargo.json @@ -0,0 +1,15 @@ +{ + "features": [ + "__cli", + "experimental", + "runtime", + "which-rustfmt" + ], + "package": { + "bindgen": { + "copy_out": true, + "device_supported": false, + "host_first_multilib": true + } + } +} @@ -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 , } } @@ -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, @@ -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))) @@ -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, @@ -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())) }) }); @@ -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() } } @@ -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) | @@ -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(); |