Skip to content

Commit

Permalink
Auto merge of #859 - tmfink:feature-832-custom-rust-target, r=fitzgen
Browse files Browse the repository at this point in the history
Feature 832 custom rust target

Addresses #832.

Instead of specifying whether or not to use stable, specify the Rust
release to support (one of several stable/beta releases or nightly).
The `--unstable-rust` option is still accepted and implies `--rust-target nightly`.

The definitions of `RustTarget` and `RustFeatures` are created with
macros.

In order to keep the test outputs the same,
`bindgen-flags: --rust-target 1.0` was added to test headers.

**Todo:**

- [x] Create `RustFeatures`/`RustTarget` structs
- [x] Replace uses of `unstable` with `RustFeatures` query
- [x] Add new tests
- [x] Fix doc comments TODOs
  • Loading branch information
bors-servo authored Aug 4, 2017
2 parents 04fdb10 + 0bb7b9f commit de180c4
Show file tree
Hide file tree
Showing 89 changed files with 7,897 additions and 891 deletions.
18 changes: 9 additions & 9 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ impl CodeGenerator for Module {
}

if item.id() == ctx.root_module() {
if result.saw_union && !ctx.options().unstable_rust {
if result.saw_union && !ctx.options().rust_features().untagged_union() {
utils::prepend_union_types(ctx, &mut *result);
}
if result.saw_incomplete_array {
Expand Down Expand Up @@ -911,8 +911,8 @@ impl<'a> FieldCodegen<'a> for FieldData {
let field_ty = ctx.resolve_type(self.ty());
let ty = self.ty().to_rust_ty_or_opaque(ctx, &());

// NB: In unstable rust we use proper `union` types.
let ty = if parent.is_union() && !ctx.options().unstable_rust {
// NB: If supported, we use proper `union` types.
let ty = if parent.is_union() && !ctx.options().rust_features().untagged_union() {
if ctx.options().enable_cxx_namespaces {
quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>)
} else {
Expand Down Expand Up @@ -1052,8 +1052,8 @@ impl BitfieldUnit {
-> P<ast::Item> {
let ctor_name = self.ctor_name(ctx);

// If we're generating unstable Rust, add the const.
let fn_prefix = if ctx.options().unstable_rust {
// If supported, add the const.
let fn_prefix = if ctx.options().rust_features().const_fn() {
quote_tokens!(ctx.ext_cx(), pub const fn)
} else {
quote_tokens!(ctx.ext_cx(), pub fn)
Expand Down Expand Up @@ -1115,8 +1115,8 @@ impl Bitfield {
let offset = self.offset_into_unit();
let mask = self.mask();

// If we're generating unstable Rust, add the const.
let fn_prefix = if ctx.options().unstable_rust {
// If supported, add the const.
let fn_prefix = if ctx.options().rust_features().const_fn() {
quote_tokens!(ctx.ext_cx(), pub const fn)
} else {
quote_tokens!(ctx.ext_cx(), pub fn)
Expand Down Expand Up @@ -1445,7 +1445,7 @@ impl CodeGenerator for CompInfo {
}

let canonical_name = item.canonical_name(ctx);
let builder = if is_union && ctx.options().unstable_rust {
let builder = if is_union && ctx.options().rust_features().untagged_union() {
aster::AstBuilder::new()
.item()
.pub_()
Expand Down Expand Up @@ -1552,7 +1552,7 @@ impl CodeGenerator for CompInfo {
());
}

if is_union && !ctx.options().unstable_rust {
if is_union && !ctx.options().rust_features().untagged_union() {
let layout = layout.expect("Unable to get layout information?");
let ty = BlobTyBuilder::new(layout).build();
let field = StructFieldBuilder::named("bindgen_union_field")
Expand Down
187 changes: 187 additions & 0 deletions src/features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
//! Contains code for selecting features
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(unused_extern_crates)]

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; )* ) => {
/// 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)]
pub enum RustTarget {
$(
$(
#[$attr]
)*
$release,
)*
}

impl Default for RustTarget {
/// Gives the latest stable Rust version
fn default() -> RustTarget {
LATEST_STABLE_RUST
}
}

impl FromStr for RustTarget {
type Err = io::Error;

#[allow(dead_code)]
/// 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\"."))),
}
}
}

impl From<RustTarget> for String {
fn from(target: RustTarget) -> Self {
match target {
$(
RustTarget::$release => stringify!($value),
)*
}.into()
}
}
}
}

/// 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
#[allow(dead_code)]
pub static RUST_TARGET_STRINGS: &'static [&str] = &[
$(
stringify!($value),
)*
];
}
}

/// Defines macro which takes a macro
macro_rules! rust_target_base {
( $x_macro:ident ) => {
$x_macro!(
/// Rust stable 1.0
=> Stable_1_0 => 1.0;
/// Rust stable 1.19
=> Stable_1_19 => 1.19;
/// Nightly rust
=> Nightly => nightly;
);
}
}

rust_target_base!(rust_target_def);
rust_target_base!(rust_target_values_def);

/// Latest stable release of Rust
pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_19;

/// Create RustFeatures struct definition, new(), and a getter for each field
macro_rules! rust_feature_def {
( $( $( #[$attr:meta] )* => $feature:ident; )* ) => {
/// Features supported by a rust target
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct RustFeatures {
$(
$feature: bool,
)*
}

impl RustFeatures {
/// Gives a RustFeatures struct with all features disabled
fn new() -> Self {
RustFeatures {
$(
$feature: false,
)*
}
}

$(
$(
#[$attr]
)*
pub fn $feature(&self) -> bool {
self.$feature
}
)*
}
}
}

rust_feature_def!(
/// Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
=> untagged_union;
/// Constant function ([RFC 911](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md))
=> const_fn;
);

impl From<RustTarget> for RustFeatures {
fn from(rust_target: RustTarget) -> Self {
let mut features = RustFeatures::new();

if rust_target >= RustTarget::Stable_1_19 {
features.untagged_union = true;
}

if rust_target >= RustTarget::Nightly {
features.const_fn = true;
}

features
}
}

impl Default for RustFeatures {
fn default() -> Self {
let default_rust_target: RustTarget = Default::default();
Self::from(default_rust_target)
}
}

#[cfg(test)]
mod test {
#![allow(unused_imports)]
use super::*;

fn test_target(target_str: &str, target: RustTarget) {
let target_string: String = target.into();
assert_eq!(target_str, target_string);
assert_eq!(target, RustTarget::from_str(target_str).unwrap());
}

#[test]
fn str_to_target() {
test_target("1.0", RustTarget::Stable_1_0);
test_target("1.19", RustTarget::Stable_1_19);
test_target("nightly", RustTarget::Nightly);
}
}
2 changes: 1 addition & 1 deletion src/ir/analysis/derive_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveCopy<'ctx, 'gen> {
}

if info.kind() == CompKind::Union {
if !self.ctx.options().unstable_rust {
if !self.ctx.options().rust_features().untagged_union() {
// NOTE: If there's no template parameters we can derive copy
// unconditionally, since arrays are magical for rustc, and
// __BindgenUnionField always implements copy.
Expand Down
2 changes: 1 addition & 1 deletion src/ir/analysis/derive_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
);

if info.kind() == CompKind::Union {
if self.ctx.options().unstable_rust {
if self.ctx.options().rust_features().untagged_union() {
trace!(" cannot derive Debug for Rust unions");
return self.insert(id);
}
Expand Down
2 changes: 1 addition & 1 deletion src/ir/analysis/derive_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDefault<'ctx, 'gen> {
);

if info.kind() == CompKind::Union {
if self.ctx.options().unstable_rust {
if self.ctx.options().rust_features().untagged_union() {
trace!(" cannot derive Default for Rust unions");
return self.insert(id);
}
Expand Down
Loading

0 comments on commit de180c4

Please sign in to comment.