diff --git a/book/src/using-unions.md b/book/src/using-unions.md index 9ee10a92d5..9a0cc3ee9a 100644 --- a/book/src/using-unions.md +++ b/book/src/using-unions.md @@ -1,10 +1,14 @@ # Using the Union Types Generated by Bindgen -**NOTE:** As of Rust version 1.17, Rust does not have a stable `union` type. Issue [#32836](https://github.com/rust-lang/rust/issues/32836) tracks the stabilization of a `union` type in Rust. +**NOTE**: Rust 1.19 stabilized the `union` type (see Rust issue [#32836](https://github.com/rust-lang/rust/issues/32836)). -By using the flag `--unstable-rust`, bindgen will generate the preliminary unstable `union` type. +You can pass the `--rust-target` option to tell `bindgen` to target a specific version of Rust. +By default, `bindgen` will target the latest stable Rust. +The `--rust-target` option accepts a specific stable version (such as "1.0" or "1.19") or "nightly". -In general, most interactions with unions (either reading or writing) are unsafe. +**NOTE**: The `--unstable-rust` option is deprecated; use `--rust-target nightly` instead. + +In general, most interactions with unions (either reading or writing) are unsafe, meaning you must surround union accesses in an `unsafe {}` block. For this discussion, we will use the following C type definitions: @@ -31,46 +35,47 @@ typedef union { ### Library -* [`bindgen::Builder::unstable_rust()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.unstable_rust) -* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.derive_default) +* [`bindgen::Builder::rust_target()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.rust_target) +* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.derive_default) ### Command Line -* `--unstable-rust` +* `--rust-target` * `--with-derive-default` -## Using the unstable `union` version +## Which union type will Bindgen generate? -With `struct`s generated by bindgen from C, it is possible to initialize fields in a "normal" rust way: +Bindgen can emit one of two Rust types that correspond to C unions: -```rust,ignore -mod bindings; +* Rust's `union` builtin (only available in Rust >= 1.19, including nightly) +* Bindgen's `BindgenUnion` (available for all Rust targets) -fn main() { - let x = bindings::alpha_t { - a: 1, - b: -1, - }; -} -``` +Bindgen uses the following logic to determine which Rust union type to emit: + +* If the Rust target is >= 1.19 (including nightly) AND each field of the union can derive `Copy`, then generate a `union` builtin. +* Otherwise, generate a `BindgenUnion`. + +## Using the `union` builtin + +When using the `union` builtin type, there are two choices for initialization: -When using the unstable `union` type, there are two choices for initialization: Zeroed, and with a specific variant. +1. Zero +2. With a specific variant ```rust,ignore -#![feature(untagged_unions)] -mod bindings_unstable; +mod bindings_builtin_union; -fn unstable() { +fn union_builtin() { // Initalize the union to zero - let x = bindings_unstable::greek_t::default(); + let x = bindings_builtin_union::greek_t::default(); // If `--with-derive-default` option is not used, the following may be used // to initalize the union to zero: - let x = unsafe{ std::mem::zeroed::() }; + let x = unsafe { std::mem::zeroed::() }; // Or, it is possible to initialize exactly one variant of the enum: - let x = bindings_unstable::greek_t { - alfa: bindings_unstable::alpha_t { + let x = bindings_builtin_union::greek_t { + alfa: bindings_builtin_union::alpha_t { a: 1, b: -1, }, @@ -83,16 +88,17 @@ fn unstable() { } ``` -## Using the stable BindgenUnion types +## Using the `BindgenUnion` type -For versions of Rust that do not support the new `union` type, bindgen will generate types which provide union-like access to structure fields. +If the target Rust version does not support the new `union` type or there is a field that cannot derive `Copy`, then bindgen will provide union-like access to a `struct`. -Interacting with these unions is slightly different than the new `union` types. Whenever a variant of the union is accessed, it must be done through a reference. +Interacting with these unions is slightly different than the new `union` types. +You must access union variants through a reference. ```rust,ignore mod bindings; -fn stable() { +fn bindgenunion() { // `default()` or `zeroed()` may still be used with Bindgen's Union types let mut x = bindings::greek_t::default(); @@ -116,7 +122,7 @@ fn stable() { } ``` -If you attempt to access a BindgenUnion field directly, you will see errors like this: +If you attempt to access a `BindgenUnion` field directly, you will see errors like this: ```text error[E0308]: mismatched types diff --git a/src/options.rs b/src/options.rs index 6640fad475..a6a104d0ab 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,10 +1,9 @@ - use bindgen::{Builder, CodegenConfig, RUST_TARGET_STRINGS, RustTarget, builder}; use clap::{App, Arg}; use std::fs::File; use std::io::{self, Error, ErrorKind, Write, stderr}; -use std::str::FromStr; use std::path::PathBuf; +use std::str::FromStr; /// Construct a new [`Builder`](./struct.Builder.html) from command line flags. pub fn builder_from_flags( @@ -14,8 +13,10 @@ where I: Iterator, { let rust_target_help = format!( - "Version of the Rust compiler to target. Valid options are: {:?}.", - RUST_TARGET_STRINGS); + "Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.", + RUST_TARGET_STRINGS, + String::from(RustTarget::default()) + ); let matches = App::new("bindgen") .version(env!("CARGO_PKG_VERSION")) @@ -262,8 +263,10 @@ where if matches.is_present("unstable-rust") { builder = builder.rust_target(RustTarget::Nightly); - writeln!(&mut stderr(), "warning: the `--unstable-rust` option is deprecated") - .expect("Unable to write error message"); + writeln!( + &mut stderr(), + "warning: the `--unstable-rust` option is deprecated" + ).expect("Unable to write error message"); } if let Some(rust_target) = matches.value_of("rust-target") { @@ -487,18 +490,21 @@ where let path = PathBuf::from(path_str); if !path.is_absolute() { - return Err(Error::new(ErrorKind::Other, - "--rustfmt-configuration--file needs to be an absolute path!")); + return Err(Error::new( + ErrorKind::Other, + "--rustfmt-configuration--file needs to be an absolute path!", + )); } if path.to_str().is_none() { - return Err( - Error::new(ErrorKind::Other, - "--rustfmt-configuration-file contains non-valid UTF8 characters.")); + return Err(Error::new( + ErrorKind::Other, + "--rustfmt-configuration-file contains non-valid UTF8 characters.", + )); } builder = builder.rustfmt_configuration_file(Some(path)); - } + } let verbose = matches.is_present("verbose");