Skip to content

Commit 4fee077

Browse files
committed
ir: Track the codegen-reachable items, and use it instead of whitelisted_items() for code generation.
This standardizes the behavior change at #834, but without regressions. I've added a few more tests for #833 here.
1 parent 1830c2d commit 4fee077

File tree

9 files changed

+157
-30
lines changed

9 files changed

+157
-30
lines changed

src/codegen/mod.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,10 +3282,9 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
32823282

32833283
debug!("codegen: {:?}", context.options());
32843284

3285-
let whitelisted_items = context.whitelisted_items();
3286-
3285+
let codegen_items = context.codegen_items();
32873286
if context.options().emit_ir {
3288-
for &id in whitelisted_items {
3287+
for &id in codegen_items {
32893288
let item = context.resolve_item(id);
32903289
println!("ir: {:?} = {:#?}", id, item);
32913290
}
@@ -3299,7 +3298,7 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
32993298
}
33003299

33013300
context.resolve_item(context.root_module())
3302-
.codegen(context, &mut result, whitelisted_items, &());
3301+
.codegen(context, &mut result, codegen_items, &());
33033302

33043303
result.items
33053304
})

src/ir/context.rs

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,16 @@ pub struct BindgenContext<'ctx> {
157157
/// Whether a bindgen complex was generated
158158
generated_bindegen_complex: Cell<bool>,
159159

160-
/// The set of `ItemId`s that are whitelisted for code generation. This the
161-
/// very first thing computed after parsing our IR, and before running any
162-
/// of our analyses.
160+
/// The set of `ItemId`s that are whitelisted. This the very first thing
161+
/// computed after parsing our IR, and before running any of our analyses.
163162
whitelisted: Option<ItemSet>,
164163

164+
/// The set of `ItemId`s that are whitelisted for code generation _and_ that
165+
/// we should generate accounting for the codegen options.
166+
///
167+
/// It's computed right after computing the whitelisted items.
168+
codegen_items: Option<ItemSet>,
169+
165170
/// Map from an item's id to the set of template parameter items that it
166171
/// uses. See `ir::named` for more details. Always `Some` during the codegen
167172
/// phase.
@@ -182,7 +187,7 @@ pub struct BindgenContext<'ctx> {
182187
}
183188

184189
/// A traversal of whitelisted items.
185-
pub struct WhitelistedItems<'ctx, 'gen>
190+
struct WhitelistedItemsTraversal<'ctx, 'gen>
186191
where 'gen: 'ctx
187192
{
188193
ctx: &'ctx BindgenContext<'gen>,
@@ -193,7 +198,7 @@ pub struct WhitelistedItems<'ctx, 'gen>
193198
for<'a> fn(&'a BindgenContext, Edge) -> bool>,
194199
}
195200

196-
impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen>
201+
impl<'ctx, 'gen> Iterator for WhitelistedItemsTraversal<'ctx, 'gen>
197202
where 'gen: 'ctx
198203
{
199204
type Item = ItemId;
@@ -209,26 +214,23 @@ impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen>
209214
}
210215
}
211216

212-
impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen>
217+
impl<'ctx, 'gen> WhitelistedItemsTraversal<'ctx, 'gen>
213218
where 'gen: 'ctx
214219
{
215220
/// Construct a new whitelisted items traversal.
216221
pub fn new<R>(ctx: &'ctx BindgenContext<'gen>,
217-
roots: R)
218-
-> WhitelistedItems<'ctx, 'gen>
222+
roots: R,
223+
predicate: for<'a> fn(&'a BindgenContext, Edge) -> bool)
224+
-> Self
219225
where R: IntoIterator<Item = ItemId>,
220226
{
221-
let predicate = if ctx.options().whitelist_recursively {
222-
traversal::all_edges
223-
} else {
224-
traversal::no_edges
225-
};
226-
WhitelistedItems {
227+
WhitelistedItemsTraversal {
227228
ctx: ctx,
228229
traversal: ItemTraversal::new(ctx, roots, predicate)
229230
}
230231
}
231232
}
233+
232234
impl<'ctx> BindgenContext<'ctx> {
233235
/// Construct the context for the given `options`.
234236
pub fn new(options: BindgenOptions) -> Self {
@@ -303,6 +305,7 @@ impl<'ctx> BindgenContext<'ctx> {
303305
options: options,
304306
generated_bindegen_complex: Cell::new(false),
305307
whitelisted: None,
308+
codegen_items: None,
306309
used_template_parameters: None,
307310
need_bitfield_allocation: Default::default(),
308311
needs_mangling_hack: needs_mangling_hack,
@@ -770,7 +773,7 @@ impl<'ctx> BindgenContext<'ctx> {
770773
// Compute the whitelisted set after processing replacements and
771774
// resolving type refs, as those are the final mutations of the IR
772775
// graph, and their completion means that the IR graph is now frozen.
773-
self.compute_whitelisted_items();
776+
self.compute_whitelisted_and_codegen_items();
774777

775778
// Make sure to do this after processing replacements, since that messes
776779
// with the parentage and module children, and we want to assert that it
@@ -1589,15 +1592,22 @@ impl<'ctx> BindgenContext<'ctx> {
15891592
self.whitelisted.as_ref().unwrap()
15901593
}
15911594

1595+
/// Get a reference to the set of items we should generate.
1596+
pub fn codegen_items(&self) -> &ItemSet {
1597+
assert!(self.in_codegen_phase());
1598+
assert!(self.current_module == self.root_module);
1599+
self.codegen_items.as_ref().unwrap()
1600+
}
1601+
15921602
/// Compute the whitelisted items set and populate `self.whitelisted`.
1593-
fn compute_whitelisted_items(&mut self) {
1603+
fn compute_whitelisted_and_codegen_items(&mut self) {
15941604
assert!(self.in_codegen_phase());
15951605
assert!(self.current_module == self.root_module);
15961606
assert!(self.whitelisted.is_none());
15971607

1598-
self.whitelisted = Some({
1599-
let roots = self.items()
1600-
// Only consider items that are enabled for codegen.
1608+
let roots = {
1609+
let mut roots = self.items()
1610+
// Only consider roots that are enabled for codegen.
16011611
.filter(|&(_, item)| item.is_enabled_for_codegen(self))
16021612
.filter(|&(_, item)| {
16031613
// If nothing is explicitly whitelisted, then everything is fair
@@ -1657,16 +1667,43 @@ impl<'ctx> BindgenContext<'ctx> {
16571667
}
16581668
}
16591669
})
1660-
.map(|(&id, _)| id);
1670+
.map(|(&id, _)| id)
1671+
.collect::<Vec<_>>();
16611672

1662-
// The reversal preserves the expected ordering of traversal, resulting
1663-
// in more stable-ish bindgen-generated names for anonymous types (like
1664-
// unions).
1665-
let mut roots: Vec<_> = roots.collect();
1673+
// The reversal preserves the expected ordering of traversal,
1674+
// resulting in more stable-ish bindgen-generated names for
1675+
// anonymous types (like unions).
16661676
roots.reverse();
1677+
roots
1678+
};
16671679

1668-
WhitelistedItems::new(self, roots).collect()
1669-
});
1680+
let whitelisted_items_predicate =
1681+
if self.options().whitelist_recursively {
1682+
traversal::all_edges
1683+
} else {
1684+
traversal::no_edges
1685+
};
1686+
1687+
let whitelisted =
1688+
WhitelistedItemsTraversal::new(
1689+
self,
1690+
roots.clone(),
1691+
whitelisted_items_predicate,
1692+
).collect::<ItemSet>();
1693+
1694+
let codegen_items =
1695+
if self.options().whitelist_recursively {
1696+
WhitelistedItemsTraversal::new(
1697+
self,
1698+
roots.clone(),
1699+
traversal::codegen_edges,
1700+
).collect::<ItemSet>()
1701+
} else {
1702+
whitelisted.clone()
1703+
};
1704+
1705+
self.whitelisted = Some(whitelisted);
1706+
self.codegen_items = Some(codegen_items);
16701707
}
16711708

16721709
/// Convenient method for getting the prefix to use for most traits in

src/ir/traversal.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,34 @@ pub fn no_edges(_: &BindgenContext, _: Edge) -> bool {
208208
false
209209
}
210210

211+
/// A `TraversalPredicate` implementation that only follows edges to items that
212+
/// are enabled for code generation. This lets us skip considering items for
213+
/// which are not reachable from code generation.
214+
pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool {
215+
let cc = &ctx.options().codegen_config;
216+
match edge.kind {
217+
EdgeKind::Generic => ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx),
218+
219+
// We statically know the kind of item that non-generic edges can point
220+
// to, so we don't need to actually resolve the item and check
221+
// `Item::is_enabled_for_codegen`.
222+
EdgeKind::TemplateParameterDefinition |
223+
EdgeKind::TemplateArgument |
224+
EdgeKind::TemplateDeclaration |
225+
EdgeKind::BaseMember |
226+
EdgeKind::Field |
227+
EdgeKind::InnerType |
228+
EdgeKind::FunctionReturn |
229+
EdgeKind::FunctionParameter |
230+
EdgeKind::VarType |
231+
EdgeKind::TypeReference => cc.types,
232+
EdgeKind::InnerVar => cc.vars,
233+
EdgeKind::Method => cc.methods,
234+
EdgeKind::Constructor => cc.constructors,
235+
EdgeKind::Destructor => cc.destructors,
236+
}
237+
}
238+
211239
/// The storage for the set of items that have been seen (although their
212240
/// outgoing edges might not have been fully traversed yet) in an active
213241
/// traversal.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
#[repr(C)] pub struct nsTArray { pub hdr: *const () }
7+
8+
extern "C" {
9+
pub fn func() -> *mut nsTArray;
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
// If the output of this changes, please ensure issue-833-1.hpp changes too
7+
8+
#[repr(C)]
9+
#[derive(Debug, Default, Copy, Clone)]
10+
pub struct nsTArray {
11+
pub _address: u8,
12+
}

tests/expectations/tests/issue-834.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy)]
9+
pub struct U {
10+
pub _address: u8,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_U() {
14+
assert_eq!(::std::mem::size_of::<U>() , 1usize , concat ! (
15+
"Size of: " , stringify ! ( U ) ));
16+
assert_eq! (::std::mem::align_of::<U>() , 1usize , concat ! (
17+
"Alignment of " , stringify ! ( U ) ));
18+
}
19+
impl Clone for U {
20+
fn clone(&self) -> Self { *self }
21+
}

tests/headers/issue-833-1.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// bindgen-flags: --generate functions --whitelist-function func --raw-line "#[repr(C)] pub struct nsTArray { pub hdr: *const () }"
2+
3+
template<typename T>
4+
class nsTArray {
5+
static T* sFoo;
6+
};
7+
8+
extern "C" nsTArray<int>* func();

tests/headers/issue-833-2.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// bindgen-flags: --raw-line "// If the output of this changes, please ensure issue-833-1.hpp changes too"
2+
3+
template<typename T>
4+
class nsTArray {
5+
static T* sFoo;
6+
};

tests/headers/issue-834.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// bindgen-flags: --whitelist-type U --generate types
2+
3+
struct T {};
4+
struct U {
5+
void test(T a);
6+
};

0 commit comments

Comments
 (0)