Skip to content

Commit

Permalink
Re-add --rust-target to replace --unstable-rust
Browse files Browse the repository at this point in the history
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.

This also fixes the bug where unions were generated with non-Copy
fields.
  • Loading branch information
tmfink committed Aug 13, 2017
1 parent fdee9f1 commit e7fa289
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 e7fa289

Please sign in to comment.