Skip to content

Commit

Permalink
Auto merge of #892 - tmfink:feature-832-custom-rust-target, r=emilio
Browse files Browse the repository at this point in the history
Re-add --rust-target option to replace --unstable-rust

Re-apply commit. 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 nightly.

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

For each test that uses unions, there is a version that uses the latest stable
and 1.0.
  • Loading branch information
bors-servo authored Aug 14, 2017
2 parents 98d7171 + e7fa289 commit 8c71eed
Show file tree
Hide file tree
Showing 103 changed files with 8,012 additions and 961 deletions.
30 changes: 21 additions & 9 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ struct CodegenResult<'a> {
/// need to be referenced by anything.
codegen_id: &'a Cell<usize>,

/// Whether a bindgen union has been generated at least once.
saw_bindgen_union: bool,

/// Whether an union has been generated at least once.
saw_union: bool,

Expand Down Expand Up @@ -124,6 +127,7 @@ impl<'a> CodegenResult<'a> {
CodegenResult {
items: vec![],
saw_union: false,
saw_bindgen_union: false,
saw_incomplete_array: false,
saw_objc: false,
codegen_id: codegen_id,
Expand All @@ -138,6 +142,11 @@ impl<'a> CodegenResult<'a> {
self.saw_union = true;
}

fn saw_bindgen_union(&mut self) {
self.saw_union();
self.saw_bindgen_union = true;
}

fn saw_incomplete_array(&mut self) {
self.saw_incomplete_array = true;
}
Expand Down Expand Up @@ -360,7 +369,7 @@ impl CodeGenerator for Module {
}

if item.id() == ctx.root_module() {
if result.saw_union && !ctx.options().unstable_rust {
if result.saw_bindgen_union {
utils::prepend_union_types(ctx, &mut *result);
}
if result.saw_incomplete_array {
Expand Down Expand Up @@ -943,8 +952,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() && !parent.can_be_rust_union(ctx) {
if ctx.options().enable_cxx_namespaces {
quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>)
} else {
Expand Down Expand Up @@ -1077,8 +1086,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 @@ -1138,8 +1147,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 @@ -1491,7 +1500,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 && self.can_be_rust_union(ctx) {
aster::AstBuilder::new()
.item()
.pub_()
Expand Down Expand Up @@ -1571,6 +1580,9 @@ impl CodeGenerator for CompInfo {
}
if is_union {
result.saw_union();
if !self.can_be_rust_union(ctx) {
result.saw_bindgen_union();
}
}

let layout = item.kind().expect_type().layout(ctx);
Expand Down Expand Up @@ -1600,7 +1612,7 @@ impl CodeGenerator for CompInfo {
);
}

if is_union && !ctx.options().unstable_rust {
if is_union && !self.can_be_rust_union(ctx) {
let layout = layout.expect("Unable to get layout information?");
let ty = BlobTyBuilder::new(layout).build();
let field = StructFieldBuilder::named("bindgen_union_field")
Expand Down
185 changes: 185 additions & 0 deletions src/features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
//! 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;

/// 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
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
2 changes: 1 addition & 1 deletion src/ir/analysis/derive_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveHash<'ctx, 'gen> {
);

if info.kind() == CompKind::Union {
if self.ctx.options().unstable_rust {
if self.ctx.options().rust_features().untagged_union() {
trace!(" cannot derive Hash for Rust unions");
return self.insert(id);
}
Expand Down
17 changes: 17 additions & 0 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::traversal::{EdgeKind, Trace, Tracer};
use super::template::TemplateParameters;
use clang;
use codegen::struct_layout::{align_to, bytes_from_bits_pow2};
use ir::derive::CanDeriveCopy;
use parse::{ClangItemParser, ParseError};
use peeking_take_while::PeekableExt;
use std::cell::Cell;
Expand Down Expand Up @@ -1316,6 +1317,22 @@ impl CompInfo {
pub fn compute_bitfield_units(&mut self, ctx: &BindgenContext) {
self.fields.compute_bitfield_units(ctx);
}

/// Returns whether the current union can be represented as a Rust `union`
///
/// Requirements:
/// 1. Current RustTarget allows for `untagged_union`
/// 2. Each field can derive `Copy`
pub fn can_be_rust_union(&self, ctx: &BindgenContext) -> bool {
ctx.options().rust_features().untagged_union() &&
self.fields().iter().all(|f|
match *f {
Field::DataMember(ref field_data) => field_data.ty().can_derive_copy(ctx),
Field::Bitfields(_) => false,
}
)
}

}

impl DotAttributes for CompInfo {
Expand Down
Loading

0 comments on commit 8c71eed

Please sign in to comment.