Skip to content

Commit 7bd2329

Browse files
Add --blocklist-file option (#2097)
Update Item to hold a `clang::SourceLocation` and use this to allow blocklisting based on filename. The existing code has a special case that always maps <stdint.h> integer types to corresponding Rust integer types, even if the C types are blocklisted. To match this special case behaviour, also treat these C <stdint.h> types as being eligible for derived Copy/Clone/Debug traits. Fixes #2096
1 parent 04f5c07 commit 7bd2329

File tree

11 files changed

+250
-14
lines changed

11 files changed

+250
-14
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ See [./csmith-fuzzing/README.md](./csmith-fuzzing/README.md) for details.
247247

248248
The `tests/quickchecking` crate generates property tests for `bindgen`.
249249
From the crate's directory you can run the tests with `cargo run`. For details
250-
on additional configuration including how to preserve / inspect the generated
251-
property tests, see
250+
on additional configuration including how to preserve / inspect the generated
251+
property tests, see
252252
[./tests/quickchecking/README.md](./tests/quickchecking/README.md).
253253

254254
## Code Overview
@@ -298,6 +298,8 @@ looking at. Here is a summary of the IR types and their relationships:
298298
* Its type's `ItemId`
299299
* Optionally, a mangled name
300300
* Optionally, a value
301+
* An optional `clang::SourceLocation` that holds the first source code
302+
location where the `Item` was encountered.
301303

302304
The IR forms a graph of interconnected and inter-referencing types and
303305
functions. The `ir::traversal` module provides IR graph traversal

book/src/blocklisting.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
If you need to provide your own custom translation of some type (for example,
44
because you need to wrap one of its fields in an `UnsafeCell`), you can
5-
explicitly blocklist
6-
generation of its definition. Uses of the blocklisted type
5+
explicitly blocklist generation of its definition. Uses of the blocklisted type
76
will still appear in other types' definitions. (If you don't want the type to
87
appear in the bindings at
98
all, [make it opaque](./opaque.md) instead of
@@ -13,14 +12,25 @@ Blocklisted types are pessimistically assumed not to be able to `derive` any
1312
traits, which can transitively affect other types' ability to `derive` traits or
1413
not.
1514

15+
The `blocklist-file` option also allows the blocklisting of all items from a
16+
particular path regex, for example to block all types defined in system headers
17+
that are transitively included.
18+
1619
### Library
1720

21+
* [`bindgen::Builder::blocklist_file`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.blocklist_file)
22+
* [`bindgen::Builder::blocklist_function`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.blocklist_function)
23+
* [`bindgen::Builder::blocklist_item`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.blocklist_item)
1824
* [`bindgen::Builder::blocklist_type`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.blocklist_type)
1925

2026
### Command Line
2127

28+
* `--blocklist-file <path>`
29+
* `--blocklist-function <function>`
30+
* `--blocklist-item <item>`
2231
* `--blocklist-type <type>`
2332

33+
2434
### Annotations
2535

2636
```cpp

src/clang.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,12 @@ impl fmt::Display for SourceLocation {
14011401
}
14021402
}
14031403

1404+
impl fmt::Debug for SourceLocation {
1405+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1406+
write!(f, "{}", self)
1407+
}
1408+
}
1409+
14041410
/// A comment in the source text.
14051411
///
14061412
/// Comments are sort of parsed by Clang, and have a tree structure.

src/ir/context.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
14231423

14241424
fn build_root_module(id: ItemId) -> Item {
14251425
let module = Module::new(Some("root".into()), ModuleKind::Normal);
1426-
Item::new(id, None, None, id, ItemKind::Module(module))
1426+
Item::new(id, None, None, id, ItemKind::Module(module), None)
14271427
}
14281428

14291429
/// Get the root module.
@@ -1733,6 +1733,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
17331733
None,
17341734
self.current_module.into(),
17351735
ItemKind::Type(sub_ty),
1736+
Some(child.location()),
17361737
);
17371738

17381739
// Bypass all the validations in add_item explicitly.
@@ -1797,6 +1798,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
17971798
None,
17981799
self.current_module.into(),
17991800
ItemKind::Type(ty),
1801+
Some(location.location()),
18001802
);
18011803

18021804
// Bypass all the validations in add_item explicitly.
@@ -1930,6 +1932,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19301932
) -> TypeId {
19311933
let spelling = ty.spelling();
19321934
let layout = ty.fallible_layout(self).ok();
1935+
let location = ty.declaration().location();
19331936
let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
19341937
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
19351938
let item = Item::new(
@@ -1938,6 +1941,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19381941
None,
19391942
parent_id.unwrap_or_else(|| self.current_module.into()),
19401943
ItemKind::Type(ty),
1944+
Some(location),
19411945
);
19421946
self.add_builtin_item(item);
19431947
with_id.as_type_id_unchecked()
@@ -1998,6 +2002,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19982002
let spelling = ty.spelling();
19992003
let is_const = ty.is_const();
20002004
let layout = ty.fallible_layout(self).ok();
2005+
let location = ty.declaration().location();
20012006
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
20022007
let id = self.next_item_id();
20032008
let item = Item::new(
@@ -2006,6 +2011,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20062011
None,
20072012
self.root_module.into(),
20082013
ItemKind::Type(ty),
2014+
Some(location),
20092015
);
20102016
self.add_builtin_item(item);
20112017
Some(id.as_type_id_unchecked())
@@ -2194,6 +2200,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
21942200
None,
21952201
self.current_module.into(),
21962202
ItemKind::Module(module),
2203+
Some(cursor.location()),
21972204
);
21982205

21992206
let module_id = module.id().as_module_id_unchecked();
@@ -2241,11 +2248,6 @@ If you encounter an error missing from this list, please file an issue or a PR!"
22412248
assert!(self.in_codegen_phase());
22422249
assert!(self.current_module == self.root_module);
22432250

2244-
let cb = match self.options.parse_callbacks {
2245-
Some(ref cb) => cb,
2246-
None => return CanDerive::No,
2247-
};
2248-
22492251
*self
22502252
.blocklisted_types_implement_traits
22512253
.borrow_mut()
@@ -2255,8 +2257,27 @@ If you encounter an error missing from this list, please file an issue or a PR!"
22552257
.or_insert_with(|| {
22562258
item.expect_type()
22572259
.name()
2258-
.and_then(|name| {
2259-
cb.blocklisted_type_implements_trait(name, derive_trait)
2260+
.and_then(|name| match self.options.parse_callbacks {
2261+
Some(ref cb) => cb.blocklisted_type_implements_trait(
2262+
name,
2263+
derive_trait,
2264+
),
2265+
// Sized integer types from <stdint.h> get mapped to Rust primitive
2266+
// types regardless of whether they are blocklisted, so ensure that
2267+
// standard traits are considered derivable for them too.
2268+
None => match name {
2269+
"int8_t" | "uint8_t" | "int16_t" | "uint16_t" |
2270+
"int32_t" | "uint32_t" | "int64_t" |
2271+
"uint64_t" | "uintptr_t" | "intptr_t" |
2272+
"ptrdiff_t" => Some(CanDerive::Yes),
2273+
"size_t" if self.options.size_t_is_usize => {
2274+
Some(CanDerive::Yes)
2275+
}
2276+
"ssize_t" if self.options.size_t_is_usize => {
2277+
Some(CanDerive::Yes)
2278+
}
2279+
_ => Some(CanDerive::No),
2280+
},
22602281
})
22612282
.unwrap_or(CanDerive::No)
22622283
})

src/ir/item.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ pub struct Item {
417417
parent_id: ItemId,
418418
/// The item kind.
419419
kind: ItemKind,
420+
/// The source location of the item.
421+
location: Option<clang::SourceLocation>,
420422
}
421423

422424
impl AsRef<ItemId> for Item {
@@ -433,6 +435,7 @@ impl Item {
433435
annotations: Option<Annotations>,
434436
parent_id: ItemId,
435437
kind: ItemKind,
438+
location: Option<clang::SourceLocation>,
436439
) -> Self {
437440
debug_assert!(id != parent_id || kind.is_module());
438441
Item {
@@ -445,6 +448,7 @@ impl Item {
445448
comment,
446449
annotations: annotations.unwrap_or_default(),
447450
kind,
451+
location,
448452
}
449453
}
450454

@@ -454,10 +458,15 @@ impl Item {
454458
ty: &clang::Type,
455459
ctx: &mut BindgenContext,
456460
) -> TypeId {
461+
let location = ty.declaration().location();
457462
let ty = Opaque::from_clang_ty(ty, ctx);
458463
let kind = ItemKind::Type(ty);
459464
let parent = ctx.root_module().into();
460-
ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);
465+
ctx.add_item(
466+
Item::new(with_id, None, None, parent, kind, Some(location)),
467+
None,
468+
None,
469+
);
461470
with_id.as_type_id_unchecked()
462471
}
463472

@@ -632,6 +641,17 @@ impl Item {
632641
return true;
633642
}
634643

644+
if !ctx.options().blocklisted_files.is_empty() {
645+
if let Some(location) = &self.location {
646+
let (file, _, _, _) = location.location();
647+
if let Some(filename) = file.name() {
648+
if ctx.options().blocklisted_files.matches(&filename) {
649+
return true;
650+
}
651+
}
652+
}
653+
}
654+
635655
let path = self.path_for_allowlisting(ctx);
636656
let name = path[1..].join("::");
637657
ctx.options().blocklisted_items.matches(&name) ||
@@ -1297,7 +1317,7 @@ impl ClangItemParser for Item {
12971317
let id = ctx.next_item_id();
12981318
let module = ctx.root_module().into();
12991319
ctx.add_item(
1300-
Item::new(id, None, None, module, ItemKind::Type(ty)),
1320+
Item::new(id, None, None, module, ItemKind::Type(ty), None),
13011321
None,
13021322
None,
13031323
);
@@ -1335,6 +1355,7 @@ impl ClangItemParser for Item {
13351355
annotations,
13361356
relevant_parent_id,
13371357
ItemKind::$what(item),
1358+
Some(cursor.location()),
13381359
),
13391360
declaration,
13401361
Some(cursor),
@@ -1516,6 +1537,7 @@ impl ClangItemParser for Item {
15161537
None,
15171538
parent_id.unwrap_or_else(|| current_module.into()),
15181539
ItemKind::Type(Type::new(None, None, kind, is_const)),
1540+
Some(location.location()),
15191541
),
15201542
None,
15211543
None,
@@ -1647,6 +1669,7 @@ impl ClangItemParser for Item {
16471669
annotations,
16481670
relevant_parent_id,
16491671
ItemKind::Type(item),
1672+
Some(location.location()),
16501673
),
16511674
declaration,
16521675
Some(location),
@@ -1875,6 +1898,7 @@ impl ClangItemParser for Item {
18751898
None,
18761899
parent,
18771900
ItemKind::Type(Type::named(name)),
1901+
Some(location.location()),
18781902
);
18791903
ctx.add_type_param(item, definition);
18801904
Some(id.as_type_id_unchecked())

src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ impl Builder {
308308
(&self.options.blocklisted_types, "--blocklist-type"),
309309
(&self.options.blocklisted_functions, "--blocklist-function"),
310310
(&self.options.blocklisted_items, "--blocklist-item"),
311+
(&self.options.blocklisted_files, "--blocklist-file"),
311312
(&self.options.opaque_types, "--opaque-type"),
312313
(&self.options.allowlisted_functions, "--allowlist-function"),
313314
(&self.options.allowlisted_types, "--allowlist-type"),
@@ -821,6 +822,13 @@ impl Builder {
821822
self
822823
}
823824

825+
/// Hide any contents of the given file from the generated bindings,
826+
/// regardless of whether it's a type, function, module etc.
827+
pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
828+
self.options.blocklisted_files.insert(arg);
829+
self
830+
}
831+
824832
/// Treat the given type as opaque in the generated bindings. Regular
825833
/// expressions are supported.
826834
///
@@ -1669,6 +1677,10 @@ struct BindgenOptions {
16691677
/// blocklisted and should not appear in the generated code.
16701678
blocklisted_items: RegexSet,
16711679

1680+
/// The set of files whose contents should be blocklisted and should not
1681+
/// appear in the generated code.
1682+
blocklisted_files: RegexSet,
1683+
16721684
/// The set of types that should be treated as opaque structures in the
16731685
/// generated code.
16741686
opaque_types: RegexSet,
@@ -1982,6 +1994,7 @@ impl BindgenOptions {
19821994
&mut self.blocklisted_types,
19831995
&mut self.blocklisted_functions,
19841996
&mut self.blocklisted_items,
1997+
&mut self.blocklisted_files,
19851998
&mut self.opaque_types,
19861999
&mut self.bitfield_enums,
19872000
&mut self.constified_enums,
@@ -2029,6 +2042,7 @@ impl Default for BindgenOptions {
20292042
blocklisted_types: Default::default(),
20302043
blocklisted_functions: Default::default(),
20312044
blocklisted_items: Default::default(),
2045+
blocklisted_files: Default::default(),
20322046
opaque_types: Default::default(),
20332047
rustfmt_path: Default::default(),
20342048
depfile: Default::default(),

src/options.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ where
164164
.takes_value(true)
165165
.multiple(true)
166166
.number_of_values(1),
167+
Arg::with_name("blocklist-file")
168+
.alias("blacklist-file")
169+
.long("blocklist-file")
170+
.help("Mark all contents of <path> as hidden.")
171+
.value_name("path")
172+
.takes_value(true)
173+
.multiple(true)
174+
.number_of_values(1),
167175
Arg::with_name("no-layout-tests")
168176
.long("no-layout-tests")
169177
.help("Avoid generating layout tests for any type."),
@@ -630,6 +638,12 @@ where
630638
}
631639
}
632640

641+
if let Some(hidden_files) = matches.values_of("blocklist-file") {
642+
for file in hidden_files {
643+
builder = builder.blocklist_file(file);
644+
}
645+
}
646+
633647
if matches.is_present("builtins") {
634648
builder = builder.emit_builtins();
635649
}

0 commit comments

Comments
 (0)