Skip to content

Commit b82b14b

Browse files
committed
Add --blocklist-file option
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 rust-lang#2096
1 parent b71e73b commit b82b14b

File tree

11 files changed

+202
-14
lines changed

11 files changed

+202
-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
@@ -1406,6 +1406,12 @@ impl fmt::Display for SourceLocation {
14061406
}
14071407
}
14081408

1409+
impl fmt::Debug for SourceLocation {
1410+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1411+
write!(f, "{}", self)
1412+
}
1413+
}
1414+
14091415
/// A comment in the source text.
14101416
///
14111417
/// 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
@@ -1420,7 +1420,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
14201420

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

14261426
/// Get the root module.
@@ -1730,6 +1730,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
17301730
None,
17311731
self.current_module.into(),
17321732
ItemKind::Type(sub_ty),
1733+
Some(child.location()),
17331734
);
17341735

17351736
// Bypass all the validations in add_item explicitly.
@@ -1794,6 +1795,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
17941795
None,
17951796
self.current_module.into(),
17961797
ItemKind::Type(ty),
1798+
Some(location.location()),
17971799
);
17981800

17991801
// Bypass all the validations in add_item explicitly.
@@ -1927,6 +1929,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19271929
) -> TypeId {
19281930
let spelling = ty.spelling();
19291931
let layout = ty.fallible_layout(self).ok();
1932+
let location = ty.declaration().location();
19301933
let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
19311934
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
19321935
let item = Item::new(
@@ -1935,6 +1938,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19351938
None,
19361939
parent_id.unwrap_or(self.current_module.into()),
19371940
ItemKind::Type(ty),
1941+
Some(location),
19381942
);
19391943
self.add_builtin_item(item);
19401944
with_id.as_type_id_unchecked()
@@ -1995,6 +1999,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19951999
let spelling = ty.spelling();
19962000
let is_const = ty.is_const();
19972001
let layout = ty.fallible_layout(self).ok();
2002+
let location = ty.declaration().location();
19982003
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
19992004
let id = self.next_item_id();
20002005
let item = Item::new(
@@ -2003,6 +2008,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20032008
None,
20042009
self.root_module.into(),
20052010
ItemKind::Type(ty),
2011+
Some(location),
20062012
);
20072013
self.add_builtin_item(item);
20082014
Some(id.as_type_id_unchecked())
@@ -2196,6 +2202,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
21962202
None,
21972203
self.current_module.into(),
21982204
ItemKind::Module(module),
2205+
Some(cursor.location()),
21992206
);
22002207

22012208
let module_id = module.id().as_module_id_unchecked();
@@ -2243,11 +2250,6 @@ If you encounter an error missing from this list, please file an issue or a PR!"
22432250
assert!(self.in_codegen_phase());
22442251
assert!(self.current_module == self.root_module);
22452252

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

src/ir/item.rs

Lines changed: 24 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: comment,
446449
annotations: annotations.unwrap_or_default(),
447450
kind: kind,
451+
location: 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

@@ -635,6 +644,15 @@ impl Item {
635644
return true;
636645
}
637646

647+
if let Some(location) = &self.location {
648+
let (file, _, _, _) = location.location();
649+
if let Some(filename) = file.name() {
650+
if ctx.options().blocklisted_files.matches(&filename) {
651+
return true;
652+
}
653+
}
654+
}
655+
638656
let path = self.path_for_allowlisting(ctx);
639657
let name = path[1..].join("::");
640658
ctx.options().blocklisted_items.matches(&name) ||
@@ -1307,7 +1325,7 @@ impl ClangItemParser for Item {
13071325
let id = ctx.next_item_id();
13081326
let module = ctx.root_module().into();
13091327
ctx.add_item(
1310-
Item::new(id, None, None, module, ItemKind::Type(ty)),
1328+
Item::new(id, None, None, module, ItemKind::Type(ty), None),
13111329
None,
13121330
None,
13131331
);
@@ -1345,6 +1363,7 @@ impl ClangItemParser for Item {
13451363
annotations,
13461364
relevant_parent_id,
13471365
ItemKind::$what(item),
1366+
Some(cursor.location()),
13481367
),
13491368
declaration,
13501369
Some(cursor),
@@ -1526,6 +1545,7 @@ impl ClangItemParser for Item {
15261545
None,
15271546
parent_id.unwrap_or(current_module.into()),
15281547
ItemKind::Type(Type::new(None, None, kind, is_const)),
1548+
Some(location.location()),
15291549
),
15301550
None,
15311551
None,
@@ -1657,6 +1677,7 @@ impl ClangItemParser for Item {
16571677
annotations,
16581678
relevant_parent_id,
16591679
ItemKind::Type(item),
1680+
Some(location.location()),
16601681
),
16611682
declaration,
16621683
Some(location),
@@ -1889,6 +1910,7 @@ impl ClangItemParser for Item {
18891910
None,
18901911
parent,
18911912
ItemKind::Type(Type::named(name)),
1913+
Some(location.location()),
18921914
);
18931915
ctx.add_type_param(item, definition);
18941916
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)