diff options
-rw-r--r-- | src/codegen/mod.rs | 4 | ||||
-rw-r--r-- | src/ir/context.rs | 87 | ||||
-rw-r--r-- | src/lib.rs | 15 | ||||
-rw-r--r-- | src/options.rs | 7 | ||||
-rw-r--r-- | tests/expectations/tests/do-not-derive-copy.rs | 28 | ||||
-rw-r--r-- | tests/headers/do-not-derive-copy.hpp | 5 |
6 files changed, 108 insertions, 38 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index f47787af..4697ba21 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1493,7 +1493,9 @@ impl CodeGenerator for CompInfo { needs_default_impl = ctx.options().derive_default; } - if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { + if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() && + ctx.options().derive_copy + { derives.push("Copy"); if used_template_params.is_some() { // FIXME: This requires extra logic if you have a big array in a diff --git a/src/ir/context.rs b/src/ir/context.rs index 3bb8b5d9..cfbb3766 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -321,55 +321,69 @@ where } } +/// Returns the effective target, and whether it was explicitly specified on the +/// clang flags. +fn find_effective_target(clang_args: &[String]) -> (String, bool) { + use std::env; + + for opt in clang_args { + if opt.starts_with("--target=") { + let mut split = opt.split('='); + split.next(); + return (split.next().unwrap().to_owned(), true); + } + } + + // If we're running from a build script, try to find the cargo target. + if let Ok(t) = env::var("TARGET") { + return (t, false) + } + + const HOST_TARGET: &'static str = + include_str!(concat!(env!("OUT_DIR"), "/host-target.txt")); + (HOST_TARGET.to_owned(), false) +} + impl<'ctx> BindgenContext<'ctx> { /// Construct the context for the given `options`. pub fn new(options: BindgenOptions) -> Self { use clang_sys; + // TODO(emilio): Use the CXTargetInfo here when available. + // + // see: https://reviews.llvm.org/D32389 + let (effective_target, explicit_target) = + find_effective_target(&options.clang_args); + let index = clang::Index::new(false, true); let parse_options = clang_sys::CXTranslationUnit_DetailedPreprocessingRecord; - let translation_unit = clang::TranslationUnit::parse( - &index, - "", - &options.clang_args, - &options.input_unsaved_files, - parse_options, - ).expect("TranslationUnit::parse failed"); - // TODO(emilio): Use the CXTargetInfo here when available. - // - // see: https://reviews.llvm.org/D32389 - let mut effective_target = None; - for opt in &options.clang_args { - if opt.starts_with("--target=") { - let mut split = opt.split('='); - split.next(); - effective_target = Some(split.next().unwrap().to_owned()); - break; - } - } - - if effective_target.is_none() { - use std::env; - // If we're running from a build script, try to find the cargo - // target. - effective_target = env::var("TARGET").ok(); - } + let translation_unit = { + let clang_args = if explicit_target { + Cow::Borrowed(&options.clang_args) + } else { + let mut args = Vec::with_capacity(options.clang_args.len() + 1); + args.push(format!("--target={}", effective_target)); + args.extend_from_slice(&options.clang_args); + Cow::Owned(args) + }; - if effective_target.is_none() { - const HOST_TARGET: &'static str = - include_str!(concat!(env!("OUT_DIR"), "/host-target.txt")); - effective_target = Some(HOST_TARGET.to_owned()); - } + clang::TranslationUnit::parse( + &index, + "", + &clang_args, + &options.input_unsaved_files, + parse_options, + ).expect("TranslationUnit::parse failed") + }; - // Mac os, iOS and Win32 need __ for mangled symbols but rust will automatically - // prepend the extra _. + // Mac os, iOS and Win32 need __ for mangled symbols but rust will + // automatically prepend the extra _. // - // We need to make sure that we don't include __ because rust will turn into - // ___. - let effective_target = effective_target.unwrap(); + // We need to make sure that we don't include __ because rust will turn + // into ___. let needs_mangling_hack = effective_target.contains("darwin") || effective_target.contains("ios") || effective_target == "i686-pc-win32"; @@ -882,7 +896,6 @@ impl<'ctx> BindgenContext<'ctx> { use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan}; use syntax::ext::base; use syntax::parse; - use std::mem; let cfg = ExpansionConfig::default("xxx".to_owned()); let sess = parse::ParseSess::new(); @@ -253,6 +253,10 @@ impl Builder { output_vector.push("--no-layout-tests".into()); } + if !self.options.derive_copy { + output_vector.push("--no-derive-copy".into()); + } + if !self.options.derive_debug { output_vector.push("--no-derive-debug".into()); } @@ -735,6 +739,12 @@ impl Builder { self } + /// Set whether `Copy` should be derived by default. + pub fn derive_copy(mut self, doit: bool) -> Self { + self.options.derive_copy = doit; + self + } + /// Set whether `Debug` should be derived by default. pub fn derive_debug(mut self, doit: bool) -> Self { self.options.derive_debug = doit; @@ -1104,6 +1114,10 @@ pub struct BindgenOptions { /// True if we should generate layout tests for generated structures. pub layout_tests: bool, + /// True if we should derive Copy trait implementations for C/C++ structures + /// and types. + pub derive_copy: bool, + /// True if we should derive Debug trait implementations for C/C++ structures /// and types. pub derive_debug: bool, @@ -1269,6 +1283,7 @@ impl Default for BindgenOptions { emit_ir: false, emit_ir_graphviz: None, layout_tests: true, + derive_copy: true, derive_debug: true, impl_debug: false, derive_default: false, diff --git a/src/options.rs b/src/options.rs index c6f5c010..aaf31953 100644 --- a/src/options.rs +++ b/src/options.rs @@ -61,6 +61,9 @@ where Arg::with_name("no-layout-tests") .long("no-layout-tests") .help("Avoid generating layout tests for any type."), + Arg::with_name("no-derive-copy") + .long("no-derive-copy") + .help("Avoid deriving Copy on any type."), Arg::with_name("no-derive-debug") .long("no-derive-debug") .help("Avoid deriving Debug on any type."), @@ -311,6 +314,10 @@ where builder = builder.layout_tests(false); } + if matches.is_present("no-derive-copy") { + builder = builder.derive_copy(false); + } + if matches.is_present("no-derive-debug") { builder = builder.derive_debug(false); } diff --git a/tests/expectations/tests/do-not-derive-copy.rs b/tests/expectations/tests/do-not-derive-copy.rs new file mode 100644 index 00000000..114b73e3 --- /dev/null +++ b/tests/expectations/tests/do-not-derive-copy.rs @@ -0,0 +1,28 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Debug, Default)] +pub struct WouldBeCopyButWeAreNotDerivingCopy { + pub x: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_WouldBeCopyButWeAreNotDerivingCopy() { + assert_eq!(::std::mem::size_of::<WouldBeCopyButWeAreNotDerivingCopy>() , + 4usize , concat ! ( + "Size of: " , stringify ! ( WouldBeCopyButWeAreNotDerivingCopy + ) )); + assert_eq! (::std::mem::align_of::<WouldBeCopyButWeAreNotDerivingCopy>() , + 4usize , concat ! ( + "Alignment of " , stringify ! ( + WouldBeCopyButWeAreNotDerivingCopy ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const WouldBeCopyButWeAreNotDerivingCopy ) ) . + x as * const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( + WouldBeCopyButWeAreNotDerivingCopy ) , "::" , stringify ! ( x + ) )); +} diff --git a/tests/headers/do-not-derive-copy.hpp b/tests/headers/do-not-derive-copy.hpp new file mode 100644 index 00000000..18c26135 --- /dev/null +++ b/tests/headers/do-not-derive-copy.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --no-derive-copy + +class WouldBeCopyButWeAreNotDerivingCopy { + int x; +}; |