summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarphone Wong <varphone@qq.com>2020-08-02 09:48:40 +0800
committerEmilio Cobos Álvarez <emilio@crisal.io>2020-08-03 18:29:07 +0200
commitff3698189cb44f900e81d2b92131b1c191acf4de (patch)
tree89b8c03fe5f29b8afebf77ead0962f1f8b217d06
parentf56fbcef788098155a10ef455284e218fe15bc7a (diff)
Add --no-debug <regex> flag
-rw-r--r--book/src/SUMMARY.md1
-rw-r--r--book/src/nodebug.md40
-rw-r--r--src/codegen/mod.rs8
-rw-r--r--src/ir/analysis/derive.rs1
-rw-r--r--src/ir/annotations.rs9
-rw-r--r--src/ir/context.rs6
-rw-r--r--src/lib.rs13
-rw-r--r--src/options.rs13
-rw-r--r--tests/expectations/tests/no_debug.rs13
-rw-r--r--tests/expectations/tests/no_debug_bypass_impl_debug.rs32
-rw-r--r--tests/expectations/tests/no_debug_opaque.rs26
-rw-r--r--tests/expectations/tests/no_debug_whitelisted.rs30
-rw-r--r--tests/headers/no_debug.hpp6
-rw-r--r--tests/headers/no_debug_bypass_impl_debug.hpp11
-rw-r--r--tests/headers/no_debug_opaque.hpp5
-rw-r--r--tests/headers/no_debug_whitelisted.hpp5
16 files changed, 216 insertions, 3 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index 1bd75cdd..e2347fb4 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -17,6 +17,7 @@
- [Treating a Type as an Opaque Blob of Bytes](./opaque.md)
- [Replacing One Type with Another](./replacing-types.md)
- [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
+ - [Preventing the Derivation of `Debug`](./nodebug.md)
- [Generating Bindings to C++](./cpp.md)
- [Generating Bindings to Objective-c](./objc.md)
- [Using Unions](./using-unions.md)
diff --git a/book/src/nodebug.md b/book/src/nodebug.md
new file mode 100644
index 00000000..251b792b
--- /dev/null
+++ b/book/src/nodebug.md
@@ -0,0 +1,40 @@
+# Preventing the Derivation of `Debug`
+
+`bindgen` will attempt to derive the `Debug` traits on a best-effort
+basis. Sometimes, it might not understand that although adding `#[derive(Debug)]` to a translated type definition will compile, it still shouldn't do
+that for reasons it can't know. In these cases, the `nodebug` annotation can be
+used to prevent bindgen to autoderive the `Debug` traits for a type.
+
+### Library
+
+* [`bindgen::Builder::no_debug`](https://docs.rs/bindgen/0.54.2/bindgen/struct.Builder.html#method.no_debug)
+
+### Command Line
+
+* `--no-debug <regex>`
+
+### Annotations
+
+```c
+/**
+ * Although bindgen can't know, this enum is not safe to format the output.
+ * the value may be combined with multiple bits in many C/C++ cases,
+ * for example:
+ *
+ * <div rustbindgen nodebug></div>
+ */
+enum AVRounding {
+ AV_ROUND_ZERO = 0,
+ AV_ROUND_INF = 1,
+ AV_ROUND_DOWN = 2,
+ AV_ROUND_UP = 3,
+ AV_ROUND_NEAR_INF = 5,
+ AV_ROUND_PASS_MINMAX = 8192,
+};
+
+// Prototype
+int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const;
+
+// Call
+int64_t pts = av_rescale_rnd(40000, 3600, 90000, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+```
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 20bf54c4..00aa68f3 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -112,7 +112,7 @@ bitflags! {
fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
let mut derivable_traits = DerivableTraits::empty();
- if item.can_derive_debug(ctx) {
+ if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
derivable_traits |= DerivableTraits::DEBUG;
}
@@ -1885,8 +1885,10 @@ impl CodeGenerator for CompInfo {
let derivable_traits = derives_of_item(item, ctx);
if !derivable_traits.contains(DerivableTraits::DEBUG) {
- needs_debug_impl =
- ctx.options().derive_debug && ctx.options().impl_debug
+ needs_debug_impl = ctx.options().derive_debug &&
+ ctx.options().impl_debug &&
+ !ctx.no_debug_by_name(item) &&
+ !item.annotations().disallow_debug();
}
if !derivable_traits.contains(DerivableTraits::DEFAULT) {
diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs
index 6858d7f1..48c544f6 100644
--- a/src/ir/analysis/derive.rs
+++ b/src/ir/analysis/derive.rs
@@ -445,6 +445,7 @@ impl DeriveTrait {
fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
match self {
DeriveTrait::Copy => ctx.no_copy_by_name(item),
+ DeriveTrait::Debug => ctx.no_debug_by_name(item),
DeriveTrait::Hash => ctx.no_hash_by_name(item),
DeriveTrait::PartialEqOrPartialOrd => {
ctx.no_partialeq_by_name(item)
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
index 98a0c042..da4ef4f7 100644
--- a/src/ir/annotations.rs
+++ b/src/ir/annotations.rs
@@ -38,6 +38,8 @@ pub struct Annotations {
/// Manually disable deriving copy/clone on this type. Only applies to
/// struct or union types.
disallow_copy: bool,
+ /// Manually disable deriving debug on this type.
+ disallow_debug: bool,
/// Whether fields should be marked as private or not. You can set this on
/// structs (it will apply to all the fields), or individual fields.
private_fields: Option<bool>,
@@ -78,6 +80,7 @@ impl Default for Annotations {
hide: false,
use_instead_of: None,
disallow_copy: false,
+ disallow_debug: false,
private_fields: None,
accessor_kind: None,
constify_enum_variant: false,
@@ -147,6 +150,11 @@ impl Annotations {
self.disallow_copy
}
+ /// Should we avoid implementing the `Debug` trait?
+ pub fn disallow_debug(&self) -> bool {
+ self.disallow_debug
+ }
+
/// Should the fields be private?
pub fn private_fields(&self) -> Option<bool> {
self.private_fields
@@ -172,6 +180,7 @@ impl Annotations {
"opaque" => self.opaque = true,
"hide" => self.hide = true,
"nocopy" => self.disallow_copy = true,
+ "nodebug" => self.disallow_debug = true,
"replaces" => {
self.use_instead_of = Some(
attr.value.split("::").map(Into::into).collect(),
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 38d73b7e..9513a41c 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -2635,6 +2635,12 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.options().no_copy_types.matches(&name)
}
+ /// Check if `--no-debug` flag is enabled for this item.
+ pub fn no_debug_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_whitelisting(self)[1..].join("::");
+ self.options().no_debug_types.matches(&name)
+ }
+
/// Check if `--no-hash` flag is enabled for this item.
pub fn no_hash_by_name(&self, item: &Item) -> bool {
let name = item.path_for_whitelisting(self)[1..].join("::");
diff --git a/src/lib.rs b/src/lib.rs
index 5a86364e..7fb2cdb8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -295,6 +295,7 @@ impl Builder {
(&self.options.whitelisted_vars, "--whitelist-var"),
(&self.options.no_partialeq_types, "--no-partialeq"),
(&self.options.no_copy_types, "--no-copy"),
+ (&self.options.no_debug_types, "--no-debug"),
(&self.options.no_hash_types, "--no-hash"),
];
@@ -1410,6 +1411,13 @@ impl Builder {
self
}
+ /// Don't derive `Debug` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_debug_types.insert(arg.into());
+ self
+ }
+
/// Don't derive `Hash` for a given type. Regular
/// expressions are supported.
pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
@@ -1691,6 +1699,9 @@ struct BindgenOptions {
/// The set of types that we should not derive `Copy` for.
no_copy_types: RegexSet,
+ /// The set of types that we should not derive `Debug` for.
+ no_debug_types: RegexSet,
+
/// The set of types that we should not derive `Hash` for.
no_hash_types: RegexSet,
@@ -1727,6 +1738,7 @@ impl BindgenOptions {
&mut self.new_type_alias_deref,
&mut self.no_partialeq_types,
&mut self.no_copy_types,
+ &mut self.no_debug_types,
&mut self.no_hash_types,
];
let record_matches = self.record_matches;
@@ -1824,6 +1836,7 @@ impl Default for BindgenOptions {
rustfmt_configuration_file: None,
no_partialeq_types: Default::default(),
no_copy_types: Default::default(),
+ no_debug_types: Default::default(),
no_hash_types: Default::default(),
array_pointers_in_arguments: false,
wasm_import_module_name: None,
diff --git a/src/options.rs b/src/options.rs
index 0add7b4c..13fbf7a4 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -430,6 +430,13 @@ where
.takes_value(true)
.multiple(true)
.number_of_values(1),
+ Arg::with_name("no-debug")
+ .long("no-debug")
+ .help("Avoid deriving Debug for types matching <regex>.")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
Arg::with_name("no-hash")
.long("no-hash")
.help("Avoid deriving Hash for types matching <regex>.")
@@ -831,6 +838,12 @@ where
}
}
+ if let Some(no_debug) = matches.values_of("no-debug") {
+ for regex in no_debug {
+ builder = builder.no_debug(regex);
+ }
+ }
+
if let Some(no_hash) = matches.values_of("no-hash") {
for regex in no_hash {
builder = builder.no_hash(regex);
diff --git a/tests/expectations/tests/no_debug.rs b/tests/expectations/tests/no_debug.rs
new file mode 100644
index 00000000..21850ecb
--- /dev/null
+++ b/tests/expectations/tests/no_debug.rs
@@ -0,0 +1,13 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+/// <div rustbindgen nodebug></div>
+#[repr(C)]
+#[derive(Default, Copy, Clone)]
+pub struct DebugButWait {
+ pub whatever: ::std::os::raw::c_int,
+}
diff --git a/tests/expectations/tests/no_debug_bypass_impl_debug.rs b/tests/expectations/tests/no_debug_bypass_impl_debug.rs
new file mode 100644
index 00000000..adb80eaa
--- /dev/null
+++ b/tests/expectations/tests/no_debug_bypass_impl_debug.rs
@@ -0,0 +1,32 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+pub struct Generic<T> {
+ pub t: [T; 40usize],
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+}
+impl<T> Default for Generic<T> {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+impl<T> ::std::fmt::Debug for Generic<T> {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ write!(f, "Generic {{ t: Array with length 40 }}")
+ }
+}
+#[repr(C)]
+pub struct NoDebug<T> {
+ pub t: [T; 40usize],
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+}
+impl<T> Default for NoDebug<T> {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
diff --git a/tests/expectations/tests/no_debug_opaque.rs b/tests/expectations/tests/no_debug_opaque.rs
new file mode 100644
index 00000000..4b657481
--- /dev/null
+++ b/tests/expectations/tests/no_debug_opaque.rs
@@ -0,0 +1,26 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[repr(align(4))]
+#[derive(Default, Copy, Clone)]
+pub struct NoDebug {
+ pub _bindgen_opaque_blob: u32,
+}
+#[test]
+fn bindgen_test_layout_NoDebug() {
+ assert_eq!(
+ ::std::mem::size_of::<NoDebug>(),
+ 4usize,
+ concat!("Size of: ", stringify!(NoDebug))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<NoDebug>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(NoDebug))
+ );
+}
diff --git a/tests/expectations/tests/no_debug_whitelisted.rs b/tests/expectations/tests/no_debug_whitelisted.rs
new file mode 100644
index 00000000..ac43e4ea
--- /dev/null
+++ b/tests/expectations/tests/no_debug_whitelisted.rs
@@ -0,0 +1,30 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Default, Copy, Clone)]
+pub struct NoDebug {
+ pub i: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_NoDebug() {
+ assert_eq!(
+ ::std::mem::size_of::<NoDebug>(),
+ 4usize,
+ concat!("Size of: ", stringify!(NoDebug))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<NoDebug>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(NoDebug))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<NoDebug>())).i as *const _ as usize },
+ 0usize,
+ concat!("Offset of field: ", stringify!(NoDebug), "::", stringify!(i))
+ );
+}
diff --git a/tests/headers/no_debug.hpp b/tests/headers/no_debug.hpp
new file mode 100644
index 00000000..2017f75d
--- /dev/null
+++ b/tests/headers/no_debug.hpp
@@ -0,0 +1,6 @@
+
+/** <div rustbindgen nodebug></div> */
+template<typename T>
+class DebugButWait {
+ int whatever;
+};
diff --git a/tests/headers/no_debug_bypass_impl_debug.hpp b/tests/headers/no_debug_bypass_impl_debug.hpp
new file mode 100644
index 00000000..a5864410
--- /dev/null
+++ b/tests/headers/no_debug_bypass_impl_debug.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: --no-debug "NoDebug" --impl-debug
+
+template<typename T>
+class Generic {
+ T t[40];
+};
+
+template<typename T>
+class NoDebug {
+ T t[40];
+};
diff --git a/tests/headers/no_debug_opaque.hpp b/tests/headers/no_debug_opaque.hpp
new file mode 100644
index 00000000..d5dc18f7
--- /dev/null
+++ b/tests/headers/no_debug_opaque.hpp
@@ -0,0 +1,5 @@
+// bindgen-flags: --opaque-type "NoDebug" --no-debug "NoDebug"
+
+class NoDebug {
+ int i;
+};
diff --git a/tests/headers/no_debug_whitelisted.hpp b/tests/headers/no_debug_whitelisted.hpp
new file mode 100644
index 00000000..7a855e81
--- /dev/null
+++ b/tests/headers/no_debug_whitelisted.hpp
@@ -0,0 +1,5 @@
+// bindgen-flags: --whitelist-type "NoDebug" --no-debug "NoDebug"
+
+class NoDebug {
+ int i;
+};