Skip to content

Commit 8536a6b

Browse files
committed
Ensure that every item is in some module's children list
Previously, if an item's parent was not a module (eg a nested class definition whose parent it the outer class definition) and the parent was not whitelisted but the item was transitively whitelisted, then we could generate uses of the item without emitting any definition for it. This could happen because we were relying on the outer type calling for code generation on its inner types, but that relies on us doing code generation for the outer type, which won't happen if the outer type is not whitelisted. This commit avoids this gotcha by ensuring that all items end up in a module's children list, and so will be code generated even if their parent is not whitelisted. Fixes rust-lang#769
1 parent 26094ea commit 8536a6b

38 files changed

+394
-66
lines changed

src/codegen/mod.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,16 @@ impl CodeGenerator for Var {
435435
}
436436
result.saw_var(&canonical_name);
437437

438+
// We can't generate bindings to static variables of templates. The
439+
// number of actual variables for a single declaration are open ended
440+
// and we don't know what instantiations do or don't exist.
441+
let type_params = item.all_template_params(ctx);
442+
if let Some(params) = type_params {
443+
if !params.is_empty() {
444+
return;
445+
}
446+
}
447+
438448
let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
439449

440450
if let Some(val) = self.val() {
@@ -759,8 +769,11 @@ impl CodeGenerator for TemplateInstantiation {
759769
let align = layout.align;
760770

761771
let name = item.canonical_name(ctx);
762-
let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}",
763-
name, item.exposed_id(ctx));
772+
let mut fn_name = format!("__bindgen_test_layout_{}_instantiation", name);
773+
let times_seen = result.overload_number(&fn_name);
774+
if times_seen > 0 {
775+
write!(&mut fn_name, "_{}", times_seen).unwrap();
776+
}
764777

765778
let fn_name = ctx.rust_ident_raw(&fn_name);
766779

src/ir/context.rs

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
44
use super::int::IntKind;
5-
use super::item::{Item, ItemCanonicalPath, ItemSet};
5+
use super::item::{Item, ItemAncestors, ItemCanonicalPath, ItemSet};
66
use super::item_kind::ItemKind;
77
use super::module::{Module, ModuleKind};
88
use super::named::{UsedTemplateParameters, analyze};
@@ -348,14 +348,29 @@ impl<'ctx> BindgenContext<'ctx> {
348348
let is_template_instantiation =
349349
is_type && item.expect_type().is_template_instantiation();
350350

351-
// Be sure to track all the generated children under namespace, even
352-
// those generated after resolving typerefs, etc.
351+
// Ensure that every item (other than the root module) is in a module's
352+
// children list. This is to make sure that every whitelisted item get's
353+
// codegen'd, even if its parent is not whitelisted. See issue #769 for
354+
// details.
353355
if item.id() != item.parent_id() {
356+
let mut added_as_child = false;
357+
354358
if let Some(mut parent) = self.items.get_mut(&item.parent_id()) {
355359
if let Some(mut module) = parent.as_module_mut() {
356-
module.children_mut().push(item.id());
360+
module.children_mut().insert(item.id());
361+
added_as_child = true;
357362
}
358363
}
364+
365+
if !added_as_child {
366+
self.items
367+
.get_mut(&self.current_module)
368+
.expect("Should always have an item for self.current_module")
369+
.as_module_mut()
370+
.expect("self.current_module should always be a module")
371+
.children_mut()
372+
.insert(item.id());
373+
}
359374
}
360375

361376
if is_type && item.expect_type().is_comp() {
@@ -620,33 +635,18 @@ impl<'ctx> BindgenContext<'ctx> {
620635
item.parent_id()
621636
};
622637

638+
// Relocate the replacement item from where it was declared, to
639+
// where the thing it is replacing was declared.
640+
//
641+
// First, we'll make sure that its parent id is correct.
623642

624-
// Reparent the item.
625643
let old_parent = self.resolve_item(replacement).parent_id();
626-
627644
if new_parent == old_parent {
645+
// Same parent and therefore also same containing
646+
// module. Nothing to do here.
628647
continue;
629648
}
630649

631-
if let Some(mut module) = self.items
632-
.get_mut(&old_parent)
633-
.unwrap()
634-
.as_module_mut() {
635-
// Deparent the replacement.
636-
let position = module.children()
637-
.iter()
638-
.position(|id| *id == replacement)
639-
.unwrap();
640-
module.children_mut().remove(position);
641-
}
642-
643-
if let Some(mut module) = self.items
644-
.get_mut(&new_parent)
645-
.unwrap()
646-
.as_module_mut() {
647-
module.children_mut().push(replacement);
648-
}
649-
650650
self.items
651651
.get_mut(&replacement)
652652
.unwrap()
@@ -655,6 +655,49 @@ impl<'ctx> BindgenContext<'ctx> {
655655
.get_mut(&id)
656656
.unwrap()
657657
.set_parent_for_replacement(old_parent);
658+
659+
// Second, make sure that it is in the correct module's children
660+
// set.
661+
662+
let old_module = {
663+
let immut_self = &*self;
664+
old_parent.ancestors(immut_self)
665+
.chain(Some(immut_self.root_module))
666+
.find(|id| {
667+
let item = immut_self.resolve_item(*id);
668+
item.as_module().map_or(false, |m| m.children().contains(&replacement))
669+
})
670+
};
671+
let old_module = old_module.expect("Every replacement item should be in a module");
672+
673+
let new_module = {
674+
let immut_self = &*self;
675+
new_parent.ancestors(immut_self).find(|id| {
676+
immut_self.resolve_item(*id).is_module()
677+
})
678+
};
679+
let new_module = new_module.unwrap_or(self.root_module);
680+
681+
if new_module == old_module {
682+
// Already in the correct module.
683+
continue;
684+
}
685+
686+
self.items
687+
.get_mut(&old_module)
688+
.unwrap()
689+
.as_module_mut()
690+
.unwrap()
691+
.children_mut()
692+
.remove(&replacement);
693+
694+
self.items
695+
.get_mut(&new_module)
696+
.unwrap()
697+
.as_module_mut()
698+
.unwrap()
699+
.children_mut()
700+
.insert(replacement);
658701
}
659702
}
660703

src/ir/module.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Intermediate representation for modules (AKA C++ namespaces).
22
3-
use super::context::{BindgenContext, ItemId};
3+
use super::context::BindgenContext;
44
use super::dot::DotAttributes;
5+
use super::item::ItemSet;
56
use clang;
67
use parse::{ClangSubItemParser, ParseError, ParseResult};
78
use parse_one;
@@ -24,7 +25,7 @@ pub struct Module {
2425
/// The kind of module this is.
2526
kind: ModuleKind,
2627
/// The children of this module, just here for convenience.
27-
children_ids: Vec<ItemId>,
28+
children: ItemSet,
2829
}
2930

3031
impl Module {
@@ -33,7 +34,7 @@ impl Module {
3334
Module {
3435
name: name,
3536
kind: kind,
36-
children_ids: vec![],
37+
children: ItemSet::new(),
3738
}
3839
}
3940

@@ -43,13 +44,13 @@ impl Module {
4344
}
4445

4546
/// Get a mutable reference to this module's children.
46-
pub fn children_mut(&mut self) -> &mut Vec<ItemId> {
47-
&mut self.children_ids
47+
pub fn children_mut(&mut self) -> &mut ItemSet {
48+
&mut self.children
4849
}
4950

5051
/// Get this module's children.
51-
pub fn children(&self) -> &[ItemId] {
52-
&self.children_ids
52+
pub fn children(&self) -> &ItemSet {
53+
&self.children
5354
}
5455

5556
/// Whether this namespace is inline.

tests/expectations/tests/anon_union.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl Default for ErrorResult {
8080
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
8181
}
8282
#[test]
83-
fn __bindgen_test_layout_TErrorResult_instantiation_1() {
83+
fn __bindgen_test_layout_TErrorResult_instantiation() {
8484
assert_eq!(::std::mem::size_of::<TErrorResult>() , 24usize , concat ! (
8585
"Size of template specialization: " , stringify ! (
8686
TErrorResult ) ));

tests/expectations/tests/class_nested.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ extern "C" {
7878
pub static mut var: A_B;
7979
}
8080
#[test]
81-
fn __bindgen_test_layout_A_D_instantiation_1() {
81+
fn __bindgen_test_layout_A_D_instantiation() {
8282
assert_eq!(::std::mem::size_of::<A_D<::std::os::raw::c_int>>() , 4usize ,
8383
concat ! (
8484
"Size of template specialization: " , stringify ! (

tests/expectations/tests/class_with_dtor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl Default for WithoutDtor {
3535
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
3636
}
3737
#[test]
38-
fn __bindgen_test_layout_HandleWithDtor_instantiation_1() {
38+
fn __bindgen_test_layout_HandleWithDtor_instantiation() {
3939
assert_eq!(::std::mem::size_of::<HandleWithDtor<::std::os::raw::c_int>>()
4040
, 8usize , concat ! (
4141
"Size of template specialization: " , stringify ! (

tests/expectations/tests/crtp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,15 @@ impl Default for DerivedFromBaseWithDestructor {
5151
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
5252
}
5353
#[test]
54-
fn __bindgen_test_layout_Base_instantiation_1() {
54+
fn __bindgen_test_layout_Base_instantiation() {
5555
assert_eq!(::std::mem::size_of::<Base>() , 1usize , concat ! (
5656
"Size of template specialization: " , stringify ! ( Base ) ));
5757
assert_eq!(::std::mem::align_of::<Base>() , 1usize , concat ! (
5858
"Alignment of template specialization: " , stringify ! ( Base )
5959
));
6060
}
6161
#[test]
62-
fn __bindgen_test_layout_BaseWithDestructor_instantiation_2() {
62+
fn __bindgen_test_layout_BaseWithDestructor_instantiation() {
6363
assert_eq!(::std::mem::size_of::<BaseWithDestructor>() , 1usize , concat !
6464
(
6565
"Size of template specialization: " , stringify ! (

tests/expectations/tests/default-template-parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ impl <T, U> Default for Foo<T, U> {
1616
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
1717
}
1818
#[test]
19-
fn __bindgen_test_layout_Foo_instantiation_1() {
19+
fn __bindgen_test_layout_Foo_instantiation() {
2020
assert_eq!(::std::mem::size_of::<Foo<bool, ::std::os::raw::c_int>>() ,
2121
8usize , concat ! (
2222
"Size of template specialization: " , stringify ! (

tests/expectations/tests/forward-declaration-autoptr.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,12 @@ impl Clone for Bar {
4141
impl Default for Bar {
4242
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
4343
}
44+
#[test]
45+
fn __bindgen_test_layout_RefPtr_instantiation() {
46+
assert_eq!(::std::mem::size_of::<RefPtr<Foo>>() , 8usize , concat ! (
47+
"Size of template specialization: " , stringify ! ( RefPtr<Foo>
48+
) ));
49+
assert_eq!(::std::mem::align_of::<RefPtr<Foo>>() , 8usize , concat ! (
50+
"Alignment of template specialization: " , stringify ! (
51+
RefPtr<Foo> ) ));
52+
}

tests/expectations/tests/gen-constructors-neg.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ fn bindgen_test_layout_Foo() {
1919
impl Clone for Foo {
2020
fn clone(&self) -> Self { *self }
2121
}
22+
extern "C" {
23+
#[link_name = "_ZN3FooC1Ei"]
24+
pub fn Foo_Foo(this: *mut Foo, a: ::std::os::raw::c_int);
25+
}

tests/expectations/tests/gen-destructors-neg.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ fn bindgen_test_layout_Foo() {
2121
"Alignment of field: " , stringify ! ( Foo ) , "::" ,
2222
stringify ! ( bar ) ));
2323
}
24+
extern "C" {
25+
#[link_name = "_ZN3FooD1Ev"]
26+
pub fn Foo_Foo_destructor(this: *mut Foo);
27+
}

tests/expectations/tests/inner_template_self.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,12 @@ impl Clone for InstantiateIt {
3636
impl Default for InstantiateIt {
3737
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
3838
}
39+
#[test]
40+
fn __bindgen_test_layout_LinkedList_instantiation() {
41+
assert_eq!(::std::mem::size_of::<LinkedList>() , 16usize , concat ! (
42+
"Size of template specialization: " , stringify ! ( LinkedList
43+
) ));
44+
assert_eq!(::std::mem::align_of::<LinkedList>() , 8usize , concat ! (
45+
"Alignment of template specialization: " , stringify ! (
46+
LinkedList ) ));
47+
}

tests/expectations/tests/issue-372.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,15 @@ pub mod root {
101101
impl Default for F {
102102
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
103103
}
104+
#[test]
105+
fn __bindgen_test_layout_C_instantiation() {
106+
assert_eq!(::std::mem::size_of::<[u64; 33usize]>() , 264usize , concat
107+
! (
108+
"Size of template specialization: " , stringify ! (
109+
[u64; 33usize] ) ));
110+
assert_eq!(::std::mem::align_of::<[u64; 33usize]>() , 8usize , concat
111+
! (
112+
"Alignment of template specialization: " , stringify ! (
113+
[u64; 33usize] ) ));
114+
}
104115
}

tests/expectations/tests/issue-569-non-type-template-params-causing-layout-test-failures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl Default for JS_AutoIdVector {
3232
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
3333
}
3434
#[test]
35-
fn __bindgen_test_layout_JS_Base_instantiation_2() {
35+
fn __bindgen_test_layout_JS_Base_instantiation() {
3636
assert_eq!(::std::mem::size_of::<JS_Base>() , 1usize , concat ! (
3737
"Size of template specialization: " , stringify ! ( JS_Base )
3838
));

tests/expectations/tests/issue-573-layout-test-failures.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,11 @@ fn bindgen_test_layout_AutoIdVector() {
2828
impl Default for AutoIdVector {
2929
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
3030
}
31+
#[test]
32+
fn __bindgen_test_layout_Outer_instantiation() {
33+
assert_eq!(::std::mem::size_of::<Outer>() , 1usize , concat ! (
34+
"Size of template specialization: " , stringify ! ( Outer ) ));
35+
assert_eq!(::std::mem::align_of::<Outer>() , 1usize , concat ! (
36+
"Alignment of template specialization: " , stringify ! ( Outer
37+
) ));
38+
}

tests/expectations/tests/issue-574-assertion-failure-in-codegen.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,11 @@ extern "C" {
3636
#[link_name = "AutoIdVector"]
3737
pub static mut AutoIdVector: _bindgen_ty_1;
3838
}
39+
#[test]
40+
fn __bindgen_test_layout_a_instantiation() {
41+
assert_eq!(::std::mem::size_of::<a>() , 1usize , concat ! (
42+
"Size of template specialization: " , stringify ! ( a ) ));
43+
assert_eq!(::std::mem::align_of::<a>() , 1usize , concat ! (
44+
"Alignment of template specialization: " , stringify ! ( a )
45+
));
46+
}

tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,11 @@ extern "C" {
7979
#[link_name = "_Z25Servo_Element_GetSnapshotv"]
8080
pub fn Servo_Element_GetSnapshot() -> A;
8181
}
82+
#[test]
83+
fn __bindgen_test_layout_f_instantiation() {
84+
assert_eq!(::std::mem::size_of::<f>() , 1usize , concat ! (
85+
"Size of template specialization: " , stringify ! ( f ) ));
86+
assert_eq!(::std::mem::align_of::<f>() , 1usize , concat ! (
87+
"Alignment of template specialization: " , stringify ! ( f )
88+
));
89+
}

tests/expectations/tests/issue-674-1.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,13 @@ pub mod root {
4343
impl Clone for CapturingContentInfo {
4444
fn clone(&self) -> Self { *self }
4545
}
46+
#[test]
47+
fn __bindgen_test_layout_Maybe_instantiation() {
48+
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
49+
"Size of template specialization: " , stringify ! ( u8 )
50+
));
51+
assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
52+
"Alignment of template specialization: " , stringify ! ( u8
53+
) ));
54+
}
4655
}

0 commit comments

Comments
 (0)