diff --git a/book/src/nocopy.md b/book/src/nocopy.md index 893f0932b6..06879ed1de 100644 --- a/book/src/nocopy.md +++ b/book/src/nocopy.md @@ -6,6 +6,16 @@ Clone)]` to a translated type definition will compile, it still shouldn't do that for reasons it can't know. In these cases, the `nocopy` annotation can be used to prevent bindgen to autoderive the `Copy` and `Clone` traits for a type. +###Library + +* [`bindgen::Builder::no_copy`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.no_copy) + +### Command Line + +* `--no-copy ` + +### Annotations + ```c /** * Although bindgen can't know, this struct is not safe to move because pthread diff --git a/src/ir/analysis/derive_copy.rs b/src/ir/analysis/derive_copy.rs index ba40141ee9..8da47a7f3a 100644 --- a/src/ir/analysis/derive_copy.rs +++ b/src/ir/analysis/derive_copy.rs @@ -143,6 +143,10 @@ impl<'ctx> MonotoneFramework for CannotDeriveCopy<'ctx> { } }; + if self.ctx.no_copy_by_name(&item) { + return self.insert(id); + } + if item.is_opaque(self.ctx, &()) { let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { l.opaque().can_trivially_derive_copy() diff --git a/src/ir/context.rs b/src/ir/context.rs index 1979e34da9..44267c7cee 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -2457,6 +2457,12 @@ impl BindgenContext { let name = item.canonical_path(self)[1..].join("::"); self.options().no_partialeq_types.matches(&name) } + + /// Check if `--no-copy` flag is enabled for this item. + pub fn no_copy_by_name(&self, item: &Item) -> bool { + let name = item.canonical_path(self)[1..].join("::"); + self.options().no_copy_types.matches(&name) + } } /// A builder struct for configuring item resolution options. diff --git a/src/lib.rs b/src/lib.rs index 7e2db0d5c9..86af0550f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -522,6 +522,20 @@ impl Builder { }) .count(); + self.options + .no_copy_types + .get_items() + .iter() + .map(|item| { + output_vector.push("--no-copy".into()); + output_vector.push( + item.trim_left_matches("^") + .trim_right_matches("$") + .into(), + ); + }) + .count(); + output_vector } @@ -1158,6 +1172,13 @@ impl Builder { self.options.no_partialeq_types.insert(arg); self } + + /// Don't derive `Copy` for a given type. Regular + /// expressions are supported. + pub fn no_copy(mut self, arg: String) -> Self { + self.options.no_copy_types.insert(arg); + self + } } /// Configuration options for generated bindings. @@ -1345,6 +1366,9 @@ struct BindgenOptions { /// The set of types that we should not derive `PartialEq` for. no_partialeq_types: RegexSet, + + /// The set of types that we should not derive `Copy` for. + no_copy_types: RegexSet, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -1363,6 +1387,7 @@ impl BindgenOptions { self.constified_enum_modules.build(); self.rustified_enums.build(); self.no_partialeq_types.build(); + self.no_copy_types.build(); } /// Update rust target version @@ -1434,6 +1459,7 @@ impl Default for BindgenOptions { rustfmt_bindings: true, rustfmt_configuration_file: None, no_partialeq_types: Default::default(), + no_copy_types: Default::default(), } } } diff --git a/src/options.rs b/src/options.rs index 64ee249eda..38b47b6a0a 100644 --- a/src/options.rs +++ b/src/options.rs @@ -285,6 +285,13 @@ where .takes_value(true) .multiple(true) .number_of_values(1), + Arg::with_name("no-copy") + .long("no-copy") + .help("Avoid deriving Copy for types matching .") + .value_name("regex") + .takes_value(true) + .multiple(true) + .number_of_values(1), ]) // .args() .get_matches_from(args); @@ -579,6 +586,12 @@ where } } + if let Some(no_partialeq) = matches.values_of("no-copy") { + for regex in no_partialeq { + builder = builder.no_copy(String::from(regex)); + } + } + let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) diff --git a/tests/expectations/tests/no_copy_opaque.rs b/tests/expectations/tests/no_copy_opaque.rs new file mode 100644 index 0000000000..8de90cd4ec --- /dev/null +++ b/tests/expectations/tests/no_copy_opaque.rs @@ -0,0 +1,24 @@ +/* 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 NoCopy { + pub _bindgen_opaque_blob: u32, +} +#[test] +fn bindgen_test_layout_NoCopy() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(NoCopy)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(NoCopy)) + ); +} diff --git a/tests/expectations/tests/no_copy_whitelisted.rs b/tests/expectations/tests/no_copy_whitelisted.rs new file mode 100644 index 0000000000..7921962550 --- /dev/null +++ b/tests/expectations/tests/no_copy_whitelisted.rs @@ -0,0 +1,34 @@ +/* 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 NoCopy { + pub i: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_NoCopy() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(NoCopy)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(NoCopy)) + ); + assert_eq!( + unsafe { &(*(0 as *const NoCopy)).i as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(NoCopy), + "::", + stringify!(i) + ) + ); +} diff --git a/tests/expectations/tests/whitelisted_item_references_no_copy.rs b/tests/expectations/tests/whitelisted_item_references_no_copy.rs new file mode 100644 index 0000000000..91b6d46a74 --- /dev/null +++ b/tests/expectations/tests/whitelisted_item_references_no_copy.rs @@ -0,0 +1,52 @@ +/* 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 NoCopy { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_NoCopy() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(NoCopy)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(NoCopy)) + ); +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct WhitelistMe { + pub a: NoCopy, +} +#[test] +fn bindgen_test_layout_WhitelistMe() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(WhitelistMe)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(WhitelistMe)) + ); + assert_eq!( + unsafe { &(*(0 as *const WhitelistMe)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(WhitelistMe), + "::", + stringify!(a) + ) + ); +} diff --git a/tests/headers/no_copy_opaque.hpp b/tests/headers/no_copy_opaque.hpp new file mode 100644 index 0000000000..c21f213af1 --- /dev/null +++ b/tests/headers/no_copy_opaque.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --opaque-type "NoCopy" --no-copy "NoCopy" + +class NoCopy { + int i; +}; diff --git a/tests/headers/no_copy_whitelisted.hpp b/tests/headers/no_copy_whitelisted.hpp new file mode 100644 index 0000000000..db44a8a7eb --- /dev/null +++ b/tests/headers/no_copy_whitelisted.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --whitelist-type "NoCopy" --no-copy "NoCopy" + +class NoCopy { + int i; +}; diff --git a/tests/headers/whitelisted_item_references_no_copy.hpp b/tests/headers/whitelisted_item_references_no_copy.hpp new file mode 100644 index 0000000000..755bbbdd49 --- /dev/null +++ b/tests/headers/whitelisted_item_references_no_copy.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --whitelist-type "WhitelistMe" --no-copy "NoCopy" + +struct NoCopy {}; + +class WhitelistMe { + NoCopy a; +};