Skip to content

Commit 75fc081

Browse files
committed
Add --no-debug <regex> flag
1 parent b424c17 commit 75fc081

16 files changed

+216
-3
lines changed

book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- [Treating a Type as an Opaque Blob of Bytes](./opaque.md)
1818
- [Replacing One Type with Another](./replacing-types.md)
1919
- [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
20+
- [Preventing the Derivation of `Debug`](./nodebug.md)
2021
- [Generating Bindings to C++](./cpp.md)
2122
- [Generating Bindings to Objective-c](./objc.md)
2223
- [Using Unions](./using-unions.md)

book/src/nodebug.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Preventing the Derivation of `Debug`
2+
3+
`bindgen` will attempt to derive the `Debug` traits on a best-effort
4+
basis. Sometimes, it might not understand that although adding `#[derive(Debug)]` to a translated type definition will compile, it still shouldn't do
5+
that for reasons it can't know. In these cases, the `nodebug` annotation can be
6+
used to prevent bindgen to autoderive the `Debug` traits for a type.
7+
8+
### Library
9+
10+
* [`bindgen::Builder::no_debug`](https://docs.rs/bindgen/0.54.2/bindgen/struct.Builder.html#method.no_debug)
11+
12+
### Command Line
13+
14+
* `--no-debug <regex>`
15+
16+
### Annotations
17+
18+
```c
19+
/**
20+
* Although bindgen can't know, this enum is not safe to format the output.
21+
* the value may be combined with multiple bits in many C/C++ cases,
22+
* for example:
23+
*
24+
* <div rustbindgen nodebug></div>
25+
*/
26+
enum AVRounding {
27+
AV_ROUND_ZERO = 0,
28+
AV_ROUND_INF = 1,
29+
AV_ROUND_DOWN = 2,
30+
AV_ROUND_UP = 3,
31+
AV_ROUND_NEAR_INF = 5,
32+
AV_ROUND_PASS_MINMAX = 8192,
33+
};
34+
35+
// Prototype
36+
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const;
37+
38+
// Call
39+
int64_t pts = av_rescale_rnd(40000, 3600, 90000, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
40+
```

src/codegen/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ bitflags! {
112112
fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
113113
let mut derivable_traits = DerivableTraits::empty();
114114

115-
if item.can_derive_debug(ctx) {
115+
if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
116116
derivable_traits |= DerivableTraits::DEBUG;
117117
}
118118

@@ -1885,8 +1885,10 @@ impl CodeGenerator for CompInfo {
18851885

18861886
let derivable_traits = derives_of_item(item, ctx);
18871887
if !derivable_traits.contains(DerivableTraits::DEBUG) {
1888-
needs_debug_impl =
1889-
ctx.options().derive_debug && ctx.options().impl_debug
1888+
needs_debug_impl = ctx.options().derive_debug
1889+
&& ctx.options().impl_debug
1890+
&& !ctx.no_debug_by_name(item)
1891+
&& !item.annotations().disallow_debug();
18901892
}
18911893

18921894
if !derivable_traits.contains(DerivableTraits::DEFAULT) {

src/ir/analysis/derive.rs

+1
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ impl DeriveTrait {
445445
fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
446446
match self {
447447
DeriveTrait::Copy => ctx.no_copy_by_name(item),
448+
DeriveTrait::Debug => ctx.no_debug_by_name(item),
448449
DeriveTrait::Hash => ctx.no_hash_by_name(item),
449450
DeriveTrait::PartialEqOrPartialOrd => {
450451
ctx.no_partialeq_by_name(item)

src/ir/annotations.rs

+9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub struct Annotations {
3838
/// Manually disable deriving copy/clone on this type. Only applies to
3939
/// struct or union types.
4040
disallow_copy: bool,
41+
/// Manually disable deriving debug on this type.
42+
disallow_debug: bool,
4143
/// Whether fields should be marked as private or not. You can set this on
4244
/// structs (it will apply to all the fields), or individual fields.
4345
private_fields: Option<bool>,
@@ -78,6 +80,7 @@ impl Default for Annotations {
7880
hide: false,
7981
use_instead_of: None,
8082
disallow_copy: false,
83+
disallow_debug: false,
8184
private_fields: None,
8285
accessor_kind: None,
8386
constify_enum_variant: false,
@@ -147,6 +150,11 @@ impl Annotations {
147150
self.disallow_copy
148151
}
149152

153+
/// Should we avoid implementing the `Debug` trait?
154+
pub fn disallow_debug(&self) -> bool {
155+
self.disallow_debug
156+
}
157+
150158
/// Should the fields be private?
151159
pub fn private_fields(&self) -> Option<bool> {
152160
self.private_fields
@@ -172,6 +180,7 @@ impl Annotations {
172180
"opaque" => self.opaque = true,
173181
"hide" => self.hide = true,
174182
"nocopy" => self.disallow_copy = true,
183+
"nodebug" => self.disallow_debug = true,
175184
"replaces" => {
176185
self.use_instead_of = Some(
177186
attr.value.split("::").map(Into::into).collect(),

src/ir/context.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2635,6 +2635,12 @@ If you encounter an error missing from this list, please file an issue or a PR!"
26352635
self.options().no_copy_types.matches(&name)
26362636
}
26372637

2638+
/// Check if `--no-debug` flag is enabled for this item.
2639+
pub fn no_debug_by_name(&self, item: &Item) -> bool {
2640+
let name = item.path_for_whitelisting(self)[1..].join("::");
2641+
self.options().no_debug_types.matches(&name)
2642+
}
2643+
26382644
/// Check if `--no-hash` flag is enabled for this item.
26392645
pub fn no_hash_by_name(&self, item: &Item) -> bool {
26402646
let name = item.path_for_whitelisting(self)[1..].join("::");

src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ impl Builder {
295295
(&self.options.whitelisted_vars, "--whitelist-var"),
296296
(&self.options.no_partialeq_types, "--no-partialeq"),
297297
(&self.options.no_copy_types, "--no-copy"),
298+
(&self.options.no_debug_types, "--no-debug"),
298299
(&self.options.no_hash_types, "--no-hash"),
299300
];
300301

@@ -1410,6 +1411,13 @@ impl Builder {
14101411
self
14111412
}
14121413

1414+
/// Don't derive `Debug` for a given type. Regular
1415+
/// expressions are supported.
1416+
pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
1417+
self.options.no_debug_types.insert(arg.into());
1418+
self
1419+
}
1420+
14131421
/// Don't derive `Hash` for a given type. Regular
14141422
/// expressions are supported.
14151423
pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
@@ -1691,6 +1699,9 @@ struct BindgenOptions {
16911699
/// The set of types that we should not derive `Copy` for.
16921700
no_copy_types: RegexSet,
16931701

1702+
/// The set of types that we should not derive `Debug` for.
1703+
no_debug_types: RegexSet,
1704+
16941705
/// The set of types that we should not derive `Hash` for.
16951706
no_hash_types: RegexSet,
16961707

@@ -1727,6 +1738,7 @@ impl BindgenOptions {
17271738
&mut self.new_type_alias_deref,
17281739
&mut self.no_partialeq_types,
17291740
&mut self.no_copy_types,
1741+
&mut self.no_debug_types,
17301742
&mut self.no_hash_types,
17311743
];
17321744
let record_matches = self.record_matches;
@@ -1824,6 +1836,7 @@ impl Default for BindgenOptions {
18241836
rustfmt_configuration_file: None,
18251837
no_partialeq_types: Default::default(),
18261838
no_copy_types: Default::default(),
1839+
no_debug_types: Default::default(),
18271840
no_hash_types: Default::default(),
18281841
array_pointers_in_arguments: false,
18291842
wasm_import_module_name: None,

src/options.rs

+13
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,13 @@ where
430430
.takes_value(true)
431431
.multiple(true)
432432
.number_of_values(1),
433+
Arg::with_name("no-debug")
434+
.long("no-debug")
435+
.help("Avoid deriving Debug for types matching <regex>.")
436+
.value_name("regex")
437+
.takes_value(true)
438+
.multiple(true)
439+
.number_of_values(1),
433440
Arg::with_name("no-hash")
434441
.long("no-hash")
435442
.help("Avoid deriving Hash for types matching <regex>.")
@@ -831,6 +838,12 @@ where
831838
}
832839
}
833840

841+
if let Some(no_debug) = matches.values_of("no-debug") {
842+
for regex in no_debug {
843+
builder = builder.no_debug(regex);
844+
}
845+
}
846+
834847
if let Some(no_hash) = matches.values_of("no-hash") {
835848
for regex in no_hash {
836849
builder = builder.no_hash(regex);

tests/expectations/tests/no_debug.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
/// <div rustbindgen nodebug></div>
9+
#[repr(C)]
10+
#[derive(Default, Copy, Clone)]
11+
pub struct CopiableButWait {
12+
pub whatever: ::std::os::raw::c_int,
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
#[repr(C)]
9+
pub struct Generic<T> {
10+
pub t: [T; 40usize],
11+
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
12+
}
13+
impl<T> Default for Generic<T> {
14+
fn default() -> Self {
15+
unsafe { ::std::mem::zeroed() }
16+
}
17+
}
18+
impl<T> ::std::fmt::Debug for Generic<T> {
19+
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
20+
write!(f, "Generic {{ t: Array with length 40 }}")
21+
}
22+
}
23+
#[repr(C)]
24+
pub struct NoDebug<T> {
25+
pub t: [T; 40usize],
26+
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
27+
}
28+
impl<T> Default for NoDebug<T> {
29+
fn default() -> Self {
30+
unsafe { ::std::mem::zeroed() }
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
#[repr(C)]
9+
#[repr(align(4))]
10+
#[derive(Default, Copy, Clone)]
11+
pub struct NoDebug {
12+
pub _bindgen_opaque_blob: u32,
13+
}
14+
#[test]
15+
fn bindgen_test_layout_NoDebug() {
16+
assert_eq!(
17+
::std::mem::size_of::<NoDebug>(),
18+
4usize,
19+
concat!("Size of: ", stringify!(NoDebug))
20+
);
21+
assert_eq!(
22+
::std::mem::align_of::<NoDebug>(),
23+
4usize,
24+
concat!("Alignment of ", stringify!(NoDebug))
25+
);
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
#[repr(C)]
9+
#[derive(Default, Copy, Clone)]
10+
pub struct NoDebug {
11+
pub i: ::std::os::raw::c_int,
12+
}
13+
#[test]
14+
fn bindgen_test_layout_NoDebug() {
15+
assert_eq!(
16+
::std::mem::size_of::<NoDebug>(),
17+
4usize,
18+
concat!("Size of: ", stringify!(NoDebug))
19+
);
20+
assert_eq!(
21+
::std::mem::align_of::<NoDebug>(),
22+
4usize,
23+
concat!("Alignment of ", stringify!(NoDebug))
24+
);
25+
assert_eq!(
26+
unsafe { &(*(::std::ptr::null::<NoDebug>())).i as *const _ as usize },
27+
0usize,
28+
concat!("Offset of field: ", stringify!(NoDebug), "::", stringify!(i))
29+
);
30+
}

tests/headers/no_debug.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
/** <div rustbindgen nodebug></div> */
3+
template<typename T>
4+
class CopiableButWait {
5+
int whatever;
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// bindgen-flags: --no-debug "NoDebug" --impl-debug
2+
3+
template<typename T>
4+
class Generic {
5+
T t[40];
6+
};
7+
8+
template<typename T>
9+
class NoDebug {
10+
T t[40];
11+
};

tests/headers/no_debug_opaque.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --opaque-type "NoDebug" --no-debug "NoDebug"
2+
3+
class NoDebug {
4+
int i;
5+
};
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --whitelist-type "NoDebug" --no-debug "NoDebug"
2+
3+
class NoDebug {
4+
int i;
5+
};

0 commit comments

Comments
 (0)