Skip to content

Commit 79447a2

Browse files
author
bors-servo
authored
Auto merge of #922 - tmfink:doc-unions, r=emilio
Update doc for unions Addresses #832 I also modified the `--help` text to print the default Rust target.
2 parents 5f627fd + 22508ce commit 79447a2

File tree

2 files changed

+54
-42
lines changed

2 files changed

+54
-42
lines changed

book/src/using-unions.md

+36-30
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Using the Union Types Generated by Bindgen
22

3-
**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.
3+
**NOTE**: Rust 1.19 stabilized the `union` type (see Rust issue [#32836](https://github.com/rust-lang/rust/issues/32836)).
44

5-
By using the flag `--unstable-rust`, bindgen will generate the preliminary unstable `union` type.
5+
You can pass the `--rust-target` option to tell `bindgen` to target a specific version of Rust.
6+
By default, `bindgen` will target the latest stable Rust.
7+
The `--rust-target` option accepts a specific stable version (such as "1.0" or "1.19") or "nightly".
68

7-
In general, most interactions with unions (either reading or writing) are unsafe.
9+
**NOTE**: The `--unstable-rust` option is deprecated; use `--rust-target nightly` instead.
10+
11+
In general, most interactions with unions (either reading or writing) are unsafe, meaning you must surround union accesses in an `unsafe {}` block.
812

913
For this discussion, we will use the following C type definitions:
1014

@@ -31,46 +35,47 @@ typedef union {
3135

3236
### Library
3337

34-
* [`bindgen::Builder::unstable_rust()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.unstable_rust)
35-
* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.derive_default)
38+
* [`bindgen::Builder::rust_target()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.rust_target) <!-- Update when live -->
39+
* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.derive_default)
3640

3741
### Command Line
3842

39-
* `--unstable-rust`
43+
* `--rust-target`
4044
* `--with-derive-default`
4145

42-
## Using the unstable `union` version
46+
## Which union type will Bindgen generate?
4347

44-
With `struct`s generated by bindgen from C, it is possible to initialize fields in a "normal" rust way:
48+
Bindgen can emit one of two Rust types that correspond to C unions:
4549

46-
```rust,ignore
47-
mod bindings;
50+
* Rust's `union` builtin (only available in Rust >= 1.19, including nightly)
51+
* Bindgen's `BindgenUnion` (available for all Rust targets)
4852

49-
fn main() {
50-
let x = bindings::alpha_t {
51-
a: 1,
52-
b: -1,
53-
};
54-
}
55-
```
53+
Bindgen uses the following logic to determine which Rust union type to emit:
54+
55+
* If the Rust target is >= 1.19 (including nightly) AND each field of the union can derive `Copy`, then generate a `union` builtin.
56+
* Otherwise, generate a `BindgenUnion`.
57+
58+
## Using the `union` builtin
59+
60+
When using the `union` builtin type, there are two choices for initialization:
5661

57-
When using the unstable `union` type, there are two choices for initialization: Zeroed, and with a specific variant.
62+
1. Zero
63+
2. With a specific variant
5864

5965
```rust,ignore
60-
#![feature(untagged_unions)]
61-
mod bindings_unstable;
66+
mod bindings_builtin_union;
6267
63-
fn unstable() {
68+
fn union_builtin() {
6469
// Initalize the union to zero
65-
let x = bindings_unstable::greek_t::default();
70+
let x = bindings_builtin_union::greek_t::default();
6671
6772
// If `--with-derive-default` option is not used, the following may be used
6873
// to initalize the union to zero:
69-
let x = unsafe{ std::mem::zeroed::<bindings_unstable::greek_t>() };
74+
let x = unsafe { std::mem::zeroed::<bindings_builtin_union::greek_t>() };
7075
7176
// Or, it is possible to initialize exactly one variant of the enum:
72-
let x = bindings_unstable::greek_t {
73-
alfa: bindings_unstable::alpha_t {
77+
let x = bindings_builtin_union::greek_t {
78+
alfa: bindings_builtin_union::alpha_t {
7479
a: 1,
7580
b: -1,
7681
},
@@ -83,16 +88,17 @@ fn unstable() {
8388
}
8489
```
8590

86-
## Using the stable BindgenUnion types
91+
## Using the `BindgenUnion` type
8792

88-
For versions of Rust that do not support the new `union` type, bindgen will generate types which provide union-like access to structure fields.
93+
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`.
8994

90-
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.
95+
Interacting with these unions is slightly different than the new `union` types.
96+
You must access union variants through a reference.
9197

9298
```rust,ignore
9399
mod bindings;
94100
95-
fn stable() {
101+
fn bindgenunion() {
96102
// `default()` or `zeroed()` may still be used with Bindgen's Union types
97103
let mut x = bindings::greek_t::default();
98104
@@ -116,7 +122,7 @@ fn stable() {
116122
}
117123
```
118124

119-
If you attempt to access a BindgenUnion field directly, you will see errors like this:
125+
If you attempt to access a `BindgenUnion` field directly, you will see errors like this:
120126

121127
```text
122128
error[E0308]: mismatched types

src/options.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
21
use bindgen::{Builder, CodegenConfig, RUST_TARGET_STRINGS, RustTarget, builder};
32
use clap::{App, Arg};
43
use std::fs::File;
54
use std::io::{self, Error, ErrorKind, Write, stderr};
6-
use std::str::FromStr;
75
use std::path::PathBuf;
6+
use std::str::FromStr;
87

98
/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
109
pub fn builder_from_flags<I>(
@@ -14,8 +13,10 @@ where
1413
I: Iterator<Item = String>,
1514
{
1615
let rust_target_help = format!(
17-
"Version of the Rust compiler to target. Valid options are: {:?}.",
18-
RUST_TARGET_STRINGS);
16+
"Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.",
17+
RUST_TARGET_STRINGS,
18+
String::from(RustTarget::default())
19+
);
1920

2021
let matches = App::new("bindgen")
2122
.version(env!("CARGO_PKG_VERSION"))
@@ -262,8 +263,10 @@ where
262263

263264
if matches.is_present("unstable-rust") {
264265
builder = builder.rust_target(RustTarget::Nightly);
265-
writeln!(&mut stderr(), "warning: the `--unstable-rust` option is deprecated")
266-
.expect("Unable to write error message");
266+
writeln!(
267+
&mut stderr(),
268+
"warning: the `--unstable-rust` option is deprecated"
269+
).expect("Unable to write error message");
267270
}
268271

269272
if let Some(rust_target) = matches.value_of("rust-target") {
@@ -487,18 +490,21 @@ where
487490
let path = PathBuf::from(path_str);
488491

489492
if !path.is_absolute() {
490-
return Err(Error::new(ErrorKind::Other,
491-
"--rustfmt-configuration--file needs to be an absolute path!"));
493+
return Err(Error::new(
494+
ErrorKind::Other,
495+
"--rustfmt-configuration--file needs to be an absolute path!",
496+
));
492497
}
493498

494499
if path.to_str().is_none() {
495-
return Err(
496-
Error::new(ErrorKind::Other,
497-
"--rustfmt-configuration-file contains non-valid UTF8 characters."));
500+
return Err(Error::new(
501+
ErrorKind::Other,
502+
"--rustfmt-configuration-file contains non-valid UTF8 characters.",
503+
));
498504
}
499505

500506
builder = builder.rustfmt_configuration_file(Some(path));
501-
}
507+
}
502508

503509
let verbose = matches.is_present("verbose");
504510

0 commit comments

Comments
 (0)