From d4ead4c3119f7af817d50f06ff32677870edcd64 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 02:31:01 -0400 Subject: [PATCH 01/18] [WIP] Generated PhantomData for used generics --- src/codegen/mod.rs | 11 ++++++++++- tests/expectations/tests/anonymous-template-types.rs | 2 ++ tests/expectations/tests/class_nested.rs | 3 +++ tests/expectations/tests/class_with_dtor.rs | 1 + tests/expectations/tests/const_tparam.rs | 1 + .../tests/forward-declaration-autoptr.rs | 1 + .../tests/forward-inherit-struct-with-fields.rs | 2 ++ tests/expectations/tests/inherit_named.rs | 1 + tests/expectations/tests/namespace.rs | 2 ++ tests/expectations/tests/nsStyleAutoArray.rs | 2 ++ tests/expectations/tests/replace_template_alias.rs | 1 + tests/expectations/tests/replaces_double.rs | 1 + tests/expectations/tests/template-param-usage-0.rs | 1 + tests/expectations/tests/template-param-usage-10.rs | 4 ++++ tests/expectations/tests/template-param-usage-12.rs | 2 ++ tests/expectations/tests/template-param-usage-13.rs | 1 + tests/expectations/tests/template-param-usage-15.rs | 1 + tests/expectations/tests/template-param-usage-2.rs | 2 ++ tests/expectations/tests/template-param-usage-3.rs | 3 +++ tests/expectations/tests/template-param-usage-4.rs | 1 + tests/expectations/tests/template-param-usage-5.rs | 1 + tests/expectations/tests/template-param-usage-7.rs | 2 ++ tests/expectations/tests/template-param-usage-8.rs | 2 ++ tests/expectations/tests/template-param-usage-9.rs | 2 ++ tests/expectations/tests/template.rs | 12 ++++++++++++ tests/expectations/tests/template_alias.rs | 1 + tests/expectations/tests/template_alias_namespace.rs | 1 + .../tests/template_typedef_transitive_param.rs | 1 + .../type_alias_partial_template_especialization.rs | 1 + tests/expectations/tests/using.rs | 1 + tests/expectations/tests/what_is_going_on.rs | 1 + tests/expectations/tests/whitelist_basic.rs | 2 ++ 32 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index fb6c839d84..fa6b65572c 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1459,11 +1459,20 @@ impl CodeGenerator for CompInfo { let mut generics = aster::AstBuilder::new().generics(); if let Some(ref params) = used_template_params { - for ty in params.iter() { + for (idx, ty) in params.iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name); + generics = generics.ty_param_id(ident); + + let prefix = ctx.trait_prefix(); + let phantom_ty = quote_ty!( + ctx.ext_cx(), + ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); + let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) + .build_ty(phantom_ty); + fields.push(phantom_field); } } diff --git a/tests/expectations/tests/anonymous-template-types.rs b/tests/expectations/tests/anonymous-template-types.rs index bb4be1055a..125ba2ff57 100644 --- a/tests/expectations/tests/anonymous-template-types.rs +++ b/tests/expectations/tests/anonymous-template-types.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Foo { pub t_member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -21,6 +22,7 @@ pub struct Bar { #[derive(Debug, Copy, Clone)] pub struct Quux { pub v_member: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Quux { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index b92976f6a0..8446cbcdf6 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -53,6 +53,7 @@ impl Clone for A_C { #[derive(Debug, Copy, Clone)] pub struct A_D { pub foo: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for A_D { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -115,11 +116,13 @@ impl Clone for D { #[derive(Debug, Copy, Clone)] pub struct Templated { pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Templated_Templated_inner { pub member_ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Templated_Templated_inner { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 495889f256..3b15b89138 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -8,6 +8,7 @@ #[derive(Debug)] pub struct HandleWithDtor { pub ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for HandleWithDtor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/const_tparam.rs b/tests/expectations/tests/const_tparam.rs index f47ca08244..7600e18eed 100644 --- a/tests/expectations/tests/const_tparam.rs +++ b/tests/expectations/tests/const_tparam.rs @@ -9,6 +9,7 @@ pub struct C { pub foo: *const T, pub bar: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for C { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/forward-declaration-autoptr.rs b/tests/expectations/tests/forward-declaration-autoptr.rs index b05984c8c8..3b5e261618 100644 --- a/tests/expectations/tests/forward-declaration-autoptr.rs +++ b/tests/expectations/tests/forward-declaration-autoptr.rs @@ -11,6 +11,7 @@ pub struct Foo([u8; 0]); #[derive(Debug, Copy, Clone)] pub struct RefPtr { pub m_inner: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for RefPtr { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/forward-inherit-struct-with-fields.rs b/tests/expectations/tests/forward-inherit-struct-with-fields.rs index ce61a5459c..1b31f62b57 100644 --- a/tests/expectations/tests/forward-inherit-struct-with-fields.rs +++ b/tests/expectations/tests/forward-inherit-struct-with-fields.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Rooted { pub _base: js_RootedBase, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for Rooted { pub struct js_RootedBase { pub foo: *mut T, pub next: *mut Rooted, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for js_RootedBase { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index 703df9ea54..a641de70b5 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -13,6 +13,7 @@ pub struct Wohoo { #[derive(Debug, Copy, Clone)] pub struct Weeee { pub _base: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Weeee { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs index 21b5a58b7a..cf47cafd22 100644 --- a/tests/expectations/tests/namespace.rs +++ b/tests/expectations/tests/namespace.rs @@ -69,6 +69,7 @@ pub mod root { pub m_c: T, pub m_c_ptr: *mut T, pub m_c_arr: [T; 10usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for C { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -81,6 +82,7 @@ pub mod root { #[derive(Debug)] pub struct D { pub m_c: root::C, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for D { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/nsStyleAutoArray.rs b/tests/expectations/tests/nsStyleAutoArray.rs index bc5f5184cb..04f01c0c3d 100644 --- a/tests/expectations/tests/nsStyleAutoArray.rs +++ b/tests/expectations/tests/nsStyleAutoArray.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct nsTArray { pub mBuff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsTArray { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for nsTArray { pub struct nsStyleAutoArray { pub mFirstElement: T, pub mOtherElements: nsTArray, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(i32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/tests/expectations/tests/replace_template_alias.rs b/tests/expectations/tests/replace_template_alias.rs index dbd0d283de..65a5332b9a 100644 --- a/tests/expectations/tests/replace_template_alias.rs +++ b/tests/expectations/tests/replace_template_alias.rs @@ -12,6 +12,7 @@ pub type JS_detail_MaybeWrapped = T; #[derive(Debug, Copy, Clone)] pub struct JS_Rooted { pub ptr: JS_detail_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for JS_Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/replaces_double.rs b/tests/expectations/tests/replaces_double.rs index 99b812db39..f7093d3d65 100644 --- a/tests/expectations/tests/replaces_double.rs +++ b/tests/expectations/tests/replaces_double.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: Rooted_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } /** *
diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs index 494001f771..a36d729a4e 100644 --- a/tests/expectations/tests/template-param-usage-0.rs +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs index 95d200b576..d41740cd7a 100644 --- a/tests/expectations/tests/template-param-usage-10.rs +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -8,6 +8,8 @@ #[derive(Debug, Copy, Clone)] pub struct DoublyIndirectUsage { pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type DoublyIndirectUsage_Aliased = T; pub type DoublyIndirectUsage_Typedefed = U; @@ -16,6 +18,8 @@ pub type DoublyIndirectUsage_Typedefed = U; pub struct DoublyIndirectUsage_IndirectUsage { pub member: DoublyIndirectUsage_Aliased, pub another: DoublyIndirectUsage_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoublyIndirectUsage_IndirectUsage { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs index 0c31111e78..fcf10615f0 100644 --- a/tests/expectations/tests/template-param-usage-12.rs +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct BaseUsesT { pub t: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for BaseUsesT { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for BaseUsesT { pub struct CrtpUsesU { pub _base: BaseUsesT>, pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for CrtpUsesU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs index c77da0973e..10e45ed1f0 100644 --- a/tests/expectations/tests/template-param-usage-13.rs +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -14,6 +14,7 @@ pub struct BaseIgnoresT { pub struct CrtpUsesU { pub _base: BaseIgnoresT, pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for CrtpUsesU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs index a653e08904..77667b454f 100644 --- a/tests/expectations/tests/template-param-usage-15.rs +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct BaseUsesT { pub usage: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for BaseUsesT { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs index 6dc21b6865..4f5987a105 100644 --- a/tests/expectations/tests/template-param-usage-2.rs +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -8,11 +8,13 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { pub also: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs index a7ff22f900..07571dcc45 100644 --- a/tests/expectations/tests/template-param-usage-3.rs +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -8,12 +8,15 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { pub also: T, pub more: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs index 31f8872dbb..7b8fe9f1ec 100644 --- a/tests/expectations/tests/template-param-usage-4.rs +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs index 5a9caf32d0..3efdfac339 100644 --- a/tests/expectations/tests/template-param-usage-5.rs +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct IndirectlyUsesTemplateParameter { pub aliased: IndirectlyUsesTemplateParameter_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type IndirectlyUsesTemplateParameter_Aliased = T; impl Default for IndirectlyUsesTemplateParameter { diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs index b0584479a7..8febe4c110 100644 --- a/tests/expectations/tests/template-param-usage-7.rs +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -9,6 +9,8 @@ pub struct DoesNotUseU { pub t: T, pub v: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoesNotUseU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs index b181cc0911..322c725718 100644 --- a/tests/expectations/tests/template-param-usage-8.rs +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -9,6 +9,8 @@ pub struct IndirectUsage { pub member1: IndirectUsage_Typedefed, pub member2: IndirectUsage_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type IndirectUsage_Typedefed = T; pub type IndirectUsage_Aliased = U; diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs index d0a3f29f6a..5f2319c448 100644 --- a/tests/expectations/tests/template-param-usage-9.rs +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -16,6 +16,8 @@ pub type DoesNotUse_Typedefed = U; pub struct DoesNotUse_IndirectUsage { pub member: DoesNotUse_Aliased, pub another: DoesNotUse_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoesNotUse_IndirectUsage { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 911b0e6ae1..682c6db9c1 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -10,6 +10,7 @@ pub struct Foo { pub m_member: T, pub m_member_ptr: *mut T, pub m_member_arr: [T; 1usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -29,6 +30,7 @@ pub type D_MyFoo = Foo<::std::os::raw::c_int>; pub struct D_U { pub m_nested_foo: D_MyFoo, pub m_baz: Z, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for D_U { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -42,6 +44,7 @@ pub struct Rooted { pub prev: *mut T, pub next: *mut Rooted<*mut ::std::os::raw::c_void>, pub ptr: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -73,6 +76,7 @@ impl Default for RootedContainer { #[derive(Debug)] pub struct WithDtor { pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for WithDtor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -133,6 +137,7 @@ impl Clone for POD { #[derive(Debug, Copy, Clone)] pub struct NestedReplaced { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedReplaced { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -141,6 +146,7 @@ impl Default for NestedReplaced { #[derive(Debug, Copy, Clone)] pub struct NestedBase { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedBase { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -149,6 +155,7 @@ impl Default for NestedBase { #[derive(Debug, Copy, Clone)] pub struct Incomplete { pub d: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Incomplete { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -159,6 +166,7 @@ pub struct NestedContainer { pub c: T, pub nested: NestedReplaced, pub inc: Incomplete, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedContainer { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -193,6 +201,7 @@ pub struct Templated { #[derive(Debug)] pub struct ReplacedWithoutDestructor { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ReplacedWithoutDestructor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -201,6 +210,7 @@ impl Default for ReplacedWithoutDestructor { #[derive(Debug)] pub struct ShouldNotBeCopiable { pub m_member: ReplacedWithoutDestructor, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ShouldNotBeCopiable { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -209,6 +219,7 @@ impl Default for ShouldNotBeCopiable { #[derive(Debug)] pub struct ShouldNotBeCopiableAsWell { pub m_member: ReplacedWithoutDestructorFwd, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ShouldNotBeCopiableAsWell { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -223,6 +234,7 @@ impl Default for ShouldNotBeCopiableAsWell { #[derive(Debug)] pub struct ReplacedWithoutDestructorFwd { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ReplacedWithoutDestructorFwd { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_alias.rs b/tests/expectations/tests/template_alias.rs index 44f7830f66..f98d165df8 100644 --- a/tests/expectations/tests/template_alias.rs +++ b/tests/expectations/tests/template_alias.rs @@ -9,6 +9,7 @@ pub type JS_detail_Wrapped = T; #[derive(Debug, Copy, Clone)] pub struct JS_Rooted { pub ptr: JS_detail_Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for JS_Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_alias_namespace.rs b/tests/expectations/tests/template_alias_namespace.rs index 90740a2d6f..491bb68cad 100644 --- a/tests/expectations/tests/template_alias_namespace.rs +++ b/tests/expectations/tests/template_alias_namespace.rs @@ -20,6 +20,7 @@ pub mod root { #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: root::JS::detail::Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index 265ab5ce1f..5f6b4c38db 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -13,6 +13,7 @@ pub struct Wrapper { #[derive(Debug, Copy, Clone)] pub struct Wrapper_Wrapped { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Wrapper_Wrapped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs index 2e0f2f4d6c..09c3248621 100644 --- a/tests/expectations/tests/type_alias_partial_template_especialization.rs +++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs @@ -9,6 +9,7 @@ pub type MaybeWrapped = A; #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/using.rs b/tests/expectations/tests/using.rs index 1638287ab6..44376b93a9 100644 --- a/tests/expectations/tests/using.rs +++ b/tests/expectations/tests/using.rs @@ -9,6 +9,7 @@ pub struct Point { pub x: T, pub y: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Point { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index e5194c02c6..fa56f04b6d 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -25,6 +25,7 @@ pub type Float = f32; pub struct PointTyped { pub x: F, pub y: F, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for PointTyped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index 8af4aba352..a83f02735b 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -9,11 +9,13 @@ pub struct WhitelistMe { pub foo: ::std::os::raw::c_int, pub bar: WhitelistMe_Inner, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct WhitelistMe_Inner { pub bar: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for WhitelistMe_Inner { fn default() -> Self { unsafe { ::std::mem::zeroed() } } From 3df362672d120bb43c58de5534259c1c747a52ad Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 10:15:39 -0400 Subject: [PATCH 02/18] fixed formatting --- build.rs | 25 ++- src/ir/mod.rs | 23 -- src/ir/module.rs | 91 -------- src/ir/objc.rs | 254 ---------------------- src/ir/traversal.rs | 476 ------------------------------------------ src/ir/var.rs | 342 ------------------------------ src/main.rs | 22 +- src/options.rs | 2 +- tests/stylo_sanity.rs | 3 +- tests/tests.rs | 27 ++- 10 files changed, 49 insertions(+), 1216 deletions(-) delete mode 100644 src/ir/mod.rs delete mode 100644 src/ir/module.rs delete mode 100644 src/ir/objc.rs delete mode 100644 src/ir/traversal.rs delete mode 100644 src/ir/var.rs diff --git a/build.rs b/build.rs index 5b8489121b..e299a671e3 100644 --- a/build.rs +++ b/build.rs @@ -26,25 +26,34 @@ mod testgen { pub fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")) + .unwrap(); println!("cargo:rerun-if-changed=tests/headers"); - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR") + .unwrap()); let headers_dir = manifest_dir.join("tests").join("headers"); - let entries = fs::read_dir(headers_dir) - .expect("Couldn't read headers dir") - .map(|result| result.expect("Couldn't read header file")); + let entries = + fs::read_dir(headers_dir) + .expect("Couldn't read headers dir") + .map(|result| result.expect("Couldn't read header file")); for entry in entries { match entry.path().extension().and_then(OsStr::to_str) { Some("h") | Some("hpp") => { - let func = entry.file_name().to_str().unwrap() + let func = entry + .file_name() + .to_str() + .unwrap() .replace(|c| !char::is_alphanumeric(c), "_") .replace("__", "_") .to_lowercase(); - writeln!(dst, "test_header!(header_{}, {:?});", - func, entry.path()).unwrap(); + writeln!(dst, + "test_header!(header_{}, {:?});", + func, + entry.path()) + .unwrap(); } _ => {} } diff --git a/src/ir/mod.rs b/src/ir/mod.rs deleted file mode 100644 index d703e53dbb..0000000000 --- a/src/ir/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! The ir module defines bindgen's intermediate representation. -//! -//! Parsing C/C++ generates the IR, while code generation outputs Rust code from -//! the IR. - -pub mod annotations; -pub mod comp; -pub mod context; -pub mod derive; -pub mod dot; -pub mod enum_ty; -pub mod function; -pub mod int; -pub mod item; -pub mod item_kind; -pub mod layout; -pub mod module; -pub mod named; -pub mod template; -pub mod traversal; -pub mod ty; -pub mod var; -pub mod objc; diff --git a/src/ir/module.rs b/src/ir/module.rs deleted file mode 100644 index ee3912c5f1..0000000000 --- a/src/ir/module.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Intermediate representation for modules (AKA C++ namespaces). - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use clang; -use parse::{ClangSubItemParser, ParseError, ParseResult}; -use parse_one; -use std::io; - -/// Whether this module is inline or not. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ModuleKind { - /// This module is not inline. - Normal, - /// This module is inline, as in `inline namespace foo {}`. - Inline, -} - -/// A module, as in, a C++ namespace. -#[derive(Clone, Debug)] -pub struct Module { - /// The name of the module, or none if it's anonymous. - name: Option, - /// The kind of module this is. - kind: ModuleKind, - /// The children of this module, just here for convenience. - children_ids: Vec, -} - -impl Module { - /// Construct a new `Module`. - pub fn new(name: Option, kind: ModuleKind) -> Self { - Module { - name: name, - kind: kind, - children_ids: vec![], - } - } - - /// Get this module's name. - pub fn name(&self) -> Option<&str> { - self.name.as_ref().map(|n| &**n) - } - - /// Get a mutable reference to this module's children. - pub fn children_mut(&mut self) -> &mut Vec { - &mut self.children_ids - } - - /// Get this module's children. - pub fn children(&self) -> &[ItemId] { - &self.children_ids - } - - /// Whether this namespace is inline. - pub fn is_inline(&self) -> bool { - self.kind == ModuleKind::Inline - } -} - -impl DotAttributes for Module { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - writeln!(out, "ModuleKind{:?}", self.kind) - } -} - -impl ClangSubItemParser for Module { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - match cursor.kind() { - CXCursor_Namespace => { - let module_id = ctx.module(cursor); - ctx.with_module(module_id, |ctx| { - cursor.visit(|cursor| { - parse_one(ctx, cursor, Some(module_id)) - }) - }); - - Ok(ParseResult::AlreadyResolved(module_id)) - } - _ => Err(ParseError::Continue), - } - } -} diff --git a/src/ir/objc.rs b/src/ir/objc.rs deleted file mode 100644 index 3a88eef8ab..0000000000 --- a/src/ir/objc.rs +++ /dev/null @@ -1,254 +0,0 @@ -//! Objective C types - -use super::context::{BindgenContext, ItemId}; -use super::function::FunctionSig; -use super::traversal::{Trace, Tracer}; -use super::ty::TypeKind; -use clang; -use clang_sys::CXChildVisit_Continue; -use clang_sys::CXCursor_ObjCCategoryDecl; -use clang_sys::CXCursor_ObjCClassMethodDecl; -use clang_sys::CXCursor_ObjCClassRef; -use clang_sys::CXCursor_ObjCInstanceMethodDecl; -use clang_sys::CXCursor_ObjCProtocolDecl; -use clang_sys::CXCursor_ObjCProtocolRef; - -/// Objective C interface as used in TypeKind -/// -/// Also protocols and categories are parsed as this type -#[derive(Debug)] -pub struct ObjCInterface { - /// The name - /// like, NSObject - name: String, - - category: Option, - - is_protocol: bool, - - conforms_to: Vec, - - /// List of the methods defined in this interfae - methods: Vec, - - class_methods: Vec, -} - -/// The objective c methods -#[derive(Debug)] -pub struct ObjCMethod { - /// The original method selector name - /// like, dataWithBytes:length: - name: String, - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - rust_name: String, - - signature: FunctionSig, - - /// Is class method? - is_class_method: bool, -} - -impl ObjCInterface { - fn new(name: &str) -> ObjCInterface { - ObjCInterface { - name: name.to_owned(), - category: None, - is_protocol: false, - conforms_to: Vec::new(), - methods: Vec::new(), - class_methods: Vec::new(), - } - } - - /// The name - /// like, NSObject - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Formats the name for rust - /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods - /// and protocols are like protocol_NSObject - pub fn rust_name(&self) -> String { - if let Some(ref cat) = self.category { - format!("{}_{}", self.name(), cat) - } else { - if self.is_protocol { - format!("protocol_{}", self.name()) - } else { - self.name().to_owned() - } - } - } - - /// List of the methods defined in this interface - pub fn methods(&self) -> &Vec { - &self.methods - } - - /// List of the class methods defined in this interface - pub fn class_methods(&self) -> &Vec { - &self.class_methods - } - - /// Parses the Objective C interface from the cursor - pub fn from_ty(cursor: &clang::Cursor, - ctx: &mut BindgenContext) - -> Option { - let name = cursor.spelling(); - let mut interface = Self::new(&name); - - if cursor.kind() == CXCursor_ObjCProtocolDecl { - interface.is_protocol = true; - } - - cursor.visit(|c| { - match c.kind() { - CXCursor_ObjCClassRef => { - if cursor.kind() == CXCursor_ObjCCategoryDecl { - // We are actually a category extension, and we found the reference - // to the original interface, so name this interface approriately - interface.name = c.spelling(); - interface.category = Some(cursor.spelling()); - } - } - CXCursor_ObjCProtocolRef => { - // Gather protocols this interface conforms to - let needle = format!("protocol_{}", c.spelling()); - let items_map = ctx.items(); - debug!("Interface {} conforms to {}, find the item", interface.name, needle); - - for (id, item) in items_map - { - if let Some(ty) = item.as_type() { - match *ty.kind() { - TypeKind::ObjCInterface(ref protocol) => { - if protocol.is_protocol - { - debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); - if Some(needle.as_ref()) == ty.name() - { - debug!("Found conforming protocol {:?}", item); - interface.conforms_to.push(*id); - break; - } - } - } - _ => {} - } - } - } - - } - CXCursor_ObjCInstanceMethodDecl | - CXCursor_ObjCClassMethodDecl => { - let name = c.spelling(); - let signature = - FunctionSig::from_ty(&c.cur_type(), &c, ctx) - .expect("Invalid function sig"); - let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; - let method = ObjCMethod::new(&name, signature, is_class_method); - interface.add_method(method); - } - _ => {} - } - CXChildVisit_Continue - }); - Some(interface) - } - - fn add_method(&mut self, method: ObjCMethod) { - if method.is_class_method { - self.class_methods.push(method); - } else { - self.methods.push(method); - } - } -} - -impl ObjCMethod { - fn new(name: &str, - signature: FunctionSig, - is_class_method: bool) - -> ObjCMethod { - let split_name: Vec<&str> = name.split(':').collect(); - - let rust_name = split_name.join("_"); - - ObjCMethod { - name: name.to_owned(), - rust_name: rust_name.to_owned(), - signature: signature, - is_class_method: is_class_method, - } - } - - /// The original method selector name - /// like, dataWithBytes:length: - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - pub fn rust_name(&self) -> &str { - self.rust_name.as_ref() - } - - /// Returns the methods signature as FunctionSig - pub fn signature(&self) -> &FunctionSig { - &self.signature - } - - /// Is this a class method? - pub fn is_class_method(&self) -> bool { - self.is_class_method - } - - /// Formats the method call - pub fn format_method_call(&self, args: &[String]) -> String { - let split_name: Vec<&str> = - self.name.split(':').filter(|p| !p.is_empty()).collect(); - - // No arguments - if args.len() == 0 && split_name.len() == 1 { - return split_name[0].to_string(); - } - - // Check right amount of arguments - if args.len() != split_name.len() { - panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", - args, - split_name); - } - - split_name.iter() - .zip(args.iter()) - .map(|parts| format!("{}:{} ", parts.0, parts.1)) - .collect::>() - .join("") - } -} - -impl Trace for ObjCInterface { - type Extra = (); - - fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) - where T: Tracer, - { - for method in &self.methods { - method.signature.trace(context, tracer, &()); - } - - for class_method in &self.class_methods { - class_method.signature.trace(context, tracer, &()); - } - - for protocol in &self.conforms_to { - tracer.visit(*protocol); - } - } -} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs deleted file mode 100644 index 95d2a45675..0000000000 --- a/src/ir/traversal.rs +++ /dev/null @@ -1,476 +0,0 @@ -//! Traversal of the graph of IR items and types. - -use super::context::{BindgenContext, ItemId}; -use super::item::ItemSet; -use std::collections::{BTreeMap, VecDeque}; - -/// An outgoing edge in the IR graph is a reference from some item to another -/// item: -/// -/// from --> to -/// -/// The `from` is left implicit: it is the concrete `Trace` implementor which -/// yielded this outgoing edge. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Edge { - to: ItemId, - kind: EdgeKind, -} - -impl Edge { - /// Construct a new edge whose referent is `to` and is of the given `kind`. - pub fn new(to: ItemId, kind: EdgeKind) -> Edge { - Edge { - to: to, - kind: kind, - } - } - - /// Get the item that this edge is pointing to. - pub fn to(&self) -> ItemId { - self.to - } - - /// Get the kind of edge that this is. - pub fn kind(&self) -> EdgeKind { - self.kind - } -} - -impl Into for Edge { - fn into(self) -> ItemId { - self.to - } -} - -/// The kind of edge reference. This is useful when we wish to only consider -/// certain kinds of edges for a particular traversal or analysis. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EdgeKind { - /// A generic, catch-all edge. - Generic, - - /// An edge from a template declaration, to the definition of a named type - /// parameter. For example, the edge from `Foo` to `T` in the following - /// snippet: - /// - /// ```C++ - /// template - /// class Foo { }; - /// ``` - TemplateParameterDefinition, - - /// An edge from a template instantiation to the template declaration that - /// is being instantiated. For example, the edge from `Foo` to - /// to `Foo`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// using Bar = Foo; - /// ``` - TemplateDeclaration, - - /// An edge from a template instantiation to its template argument. For - /// example, `Foo` to `Bar`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// class Bar { }; - /// - /// using FooBar = Foo; - /// ``` - TemplateArgument, - - /// An edge from a compound type to one of its base member types. For - /// example, the edge from `Bar` to `Foo`: - /// - /// ```C++ - /// class Foo { }; - /// - /// class Bar : public Foo { }; - /// ``` - BaseMember, - - /// An edge from a compound type to the types of one of its fields. For - /// example, the edge from `Foo` to `int`: - /// - /// ```C++ - /// class Foo { - /// int x; - /// }; - /// ``` - Field, - - /// An edge from an class or struct type to an inner type member. For - /// example, the edge from `Foo` to `Foo::Bar` here: - /// - /// ```C++ - /// class Foo { - /// struct Bar { }; - /// }; - /// ``` - InnerType, - - /// An edge from an class or struct type to an inner static variable. For - /// example, the edge from `Foo` to `Foo::BAR` here: - /// - /// ```C++ - /// class Foo { - /// static const char* BAR; - /// }; - /// ``` - InnerVar, - - /// An edge from a class or struct type to one of its method functions. For - /// example, the edge from `Foo` to `Foo::bar`: - /// - /// ```C++ - /// class Foo { - /// bool bar(int x, int y); - /// }; - /// ``` - Method, - - /// An edge from a class or struct type to one of its constructor - /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: - /// - /// ```C++ - /// class Foo { - /// int my_x; - /// int my_y; - /// - /// public: - /// Foo(int x, int y); - /// }; - /// ``` - Constructor, - - /// An edge from a function declaration to its return type. For example, the - /// edge from `foo` to `int`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionReturn, - - /// An edge from a function declaration to one of its parameter types. For - /// example, the edge from `foo` to `char*`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionParameter, - - /// An edge from a static variable to its type. For example, the edge from - /// `FOO` to `const char*`: - /// - /// ```C++ - /// static const char* FOO; - /// ``` - VarType, - - /// An edge from a non-templated alias or typedef to the referenced type. - TypeReference, -} - -/// A predicate to allow visiting only sub-sets of the whole IR graph by -/// excluding certain edges from being followed by the traversal. -pub trait TraversalPredicate { - /// Should the traversal follow this edge, and visit everything that is - /// reachable through it? - fn should_follow(&self, edge: Edge) -> bool; -} - -impl TraversalPredicate for fn(Edge) -> bool { - fn should_follow(&self, edge: Edge) -> bool { - (*self)(edge) - } -} - -/// A `TraversalPredicate` implementation that follows all edges, and therefore -/// traversals using this predicate will see the whole IR graph reachable from -/// the traversal's roots. -pub fn all_edges(_: Edge) -> bool { - true -} - -/// A `TraversalPredicate` implementation that never follows any edges, and -/// therefore traversals using this predicate will only visit the traversal's -/// roots. -pub fn no_edges(_: Edge) -> bool { - false -} - -/// The storage for the set of items that have been seen (although their -/// outgoing edges might not have been fully traversed yet) in an active -/// traversal. -pub trait TraversalStorage<'ctx, 'gen> { - /// Construct a new instance of this TraversalStorage, for a new traversal. - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; - - /// Add the given item to the storage. If the item has never been seen - /// before, return `true`. Otherwise, return `false`. - /// - /// The `from` item is the item from which we discovered this item, or is - /// `None` if this item is a root. - fn add(&mut self, from: Option, item: ItemId) -> bool; -} - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { - fn new(_: &'ctx BindgenContext<'gen>) -> Self { - ItemSet::new() - } - - fn add(&mut self, _: Option, item: ItemId) -> bool { - self.insert(item) - } -} - -/// A `TraversalStorage` implementation that keeps track of how we first reached -/// each item. This is useful for providing debug assertions with meaningful -/// diagnostic messages about dangling items. -#[derive(Debug)] -pub struct Paths<'ctx, 'gen>(BTreeMap, - &'ctx BindgenContext<'gen>) - where 'gen: 'ctx; - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> - where 'gen: 'ctx, -{ - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { - Paths(BTreeMap::new(), ctx) - } - - fn add(&mut self, from: Option, item: ItemId) -> bool { - let newly_discovered = - self.0.insert(item, from.unwrap_or(item)).is_none(); - - if self.1.resolve_item_fallible(item).is_none() { - let mut path = vec![]; - let mut current = item; - loop { - let predecessor = *self.0 - .get(¤t) - .expect("We know we found this item id, so it must have a \ - predecessor"); - if predecessor == current { - break; - } - path.push(predecessor); - current = predecessor; - } - path.reverse(); - panic!("Found reference to dangling id = {:?}\nvia path = {:?}", - item, - path); - } - - newly_discovered - } -} - -/// The queue of seen-but-not-yet-traversed items. -/// -/// Using a FIFO queue with a traversal will yield a breadth-first traversal, -/// while using a LIFO queue will result in a depth-first traversal of the IR -/// graph. -pub trait TraversalQueue: Default { - /// Add a newly discovered item to the queue. - fn push(&mut self, item: ItemId); - - /// Pop the next item to traverse, if any. - fn next(&mut self) -> Option; -} - -impl TraversalQueue for Vec { - fn push(&mut self, item: ItemId) { - self.push(item); - } - - fn next(&mut self) -> Option { - self.pop() - } -} - -impl TraversalQueue for VecDeque { - fn push(&mut self, item: ItemId) { - self.push_back(item); - } - - fn next(&mut self) -> Option { - self.pop_front() - } -} - -/// Something that can receive edges from a `Trace` implementation. -pub trait Tracer { - /// Note an edge between items. Called from within a `Trace` implementation. - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); - - /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. - fn visit(&mut self, item: ItemId) { - self.visit_kind(item, EdgeKind::Generic); - } -} - -impl Tracer for F - where F: FnMut(ItemId, EdgeKind), -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - (*self)(item, kind) - } -} - -/// Trace all of the outgoing edges to other items. Implementations should call -/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` -/// for each of their outgoing edges. -pub trait Trace { - /// If a particular type needs extra information beyond what it has in - /// `self` and `context` to find its referenced items, its implementation - /// can define this associated type, forcing callers to pass the needed - /// information through. - type Extra; - - /// Trace all of this item's outgoing edges to other items. - fn trace(&self, - context: &BindgenContext, - tracer: &mut T, - extra: &Self::Extra) - where T: Tracer; -} - -/// An graph traversal of the transitive closure of references between items. -/// -/// See `BindgenContext::whitelisted_items` for more information. -pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - ctx: &'ctx BindgenContext<'gen>, - - /// The set of items we have seen thus far in this traversal. - seen: Storage, - - /// The set of items that we have seen, but have yet to traverse. - queue: Queue, - - /// The predicate that determins which edges this traversal will follow. - predicate: Predicate, - - /// The item we are currently traversing. - currently_traversing: Option, -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, - 'gen, - Storage, - Queue, - Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - /// Begin a new traversal, starting from the given roots. - pub fn new(ctx: &'ctx BindgenContext<'gen>, - roots: R, - predicate: Predicate) - -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where R: IntoIterator, - { - let mut seen = Storage::new(ctx); - let mut queue = Queue::default(); - - for id in roots { - seen.add(None, id); - queue.push(id); - } - - ItemTraversal { - ctx: ctx, - seen: seen, - queue: queue, - predicate: predicate, - currently_traversing: None, - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - let edge = Edge::new(item, kind); - if !self.predicate.should_follow(edge) { - return; - } - - let is_newly_discovered = self.seen - .add(self.currently_traversing, item); - if is_newly_discovered { - self.queue.push(item) - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - type Item = ItemId; - - fn next(&mut self) -> Option { - let id = match self.queue.next() { - None => return None, - Some(id) => id, - }; - - let newly_discovered = self.seen.add(None, id); - debug_assert!(!newly_discovered, - "should have already seen anything we get out of our queue"); - debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), - "should only get IDs of actual items in our context during traversal"); - - self.currently_traversing = Some(id); - id.trace(self.ctx, self, &()); - self.currently_traversing = None; - - Some(id) - } -} - -/// An iterator to find any dangling items. -/// -/// See `BindgenContext::assert_no_dangling_item_traversal` for more -/// information. -pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = - ItemTraversal<'ctx, - 'gen, - Paths<'ctx, 'gen>, - VecDeque, - fn(Edge) -> bool>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[allow(dead_code)] - fn traversal_predicate_is_object_safe() { - // This should compile only if TraversalPredicate is object safe. - fn takes_by_trait_object(_: &TraversalPredicate) {} - } -} diff --git a/src/ir/var.rs b/src/ir/var.rs deleted file mode 100644 index 656a1a6dfd..0000000000 --- a/src/ir/var.rs +++ /dev/null @@ -1,342 +0,0 @@ -//! Intermediate representation of variables. - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use super::function::cursor_mangling; -use super::int::IntKind; -use super::item::Item; -use super::ty::{FloatKind, TypeKind}; -use cexpr; -use clang; -use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; -use std::io; -use std::num::Wrapping; - -/// The type for a constant variable. -#[derive(Debug)] -pub enum VarType { - /// A boolean. - Bool(bool), - /// An integer. - Int(i64), - /// A floating point number. - Float(f64), - /// A character. - Char(u8), - /// A string, not necessarily well-formed utf-8. - String(Vec), -} - -/// A `Var` is our intermediate representation of a variable. -#[derive(Debug)] -pub struct Var { - /// The name of the variable. - name: String, - /// The mangled name of the variable. - mangled_name: Option, - /// The type of the variable. - ty: ItemId, - /// The value of the variable, that needs to be suitable for `ty`. - val: Option, - /// Whether this variable is const. - is_const: bool, -} - -impl Var { - /// Construct a new `Var`. - pub fn new(name: String, - mangled: Option, - ty: ItemId, - val: Option, - is_const: bool) - -> Var { - assert!(!name.is_empty()); - Var { - name: name, - mangled_name: mangled, - ty: ty, - val: val, - is_const: is_const, - } - } - - /// Is this variable `const` qualified? - pub fn is_const(&self) -> bool { - self.is_const - } - - /// The value of this constant variable, if any. - pub fn val(&self) -> Option<&VarType> { - self.val.as_ref() - } - - /// Get this variable's type. - pub fn ty(&self) -> ItemId { - self.ty - } - - /// Get this variable's name. - pub fn name(&self) -> &str { - &self.name - } - - /// Get this variable's mangled name. - pub fn mangled_name(&self) -> Option<&str> { - self.mangled_name.as_ref().map(|n| &**n) - } -} - -impl DotAttributes for Var { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - if self.is_const { - try!(writeln!(out, "consttrue")); - } - - if let Some(ref mangled) = self.mangled_name { - try!(writeln!(out, - "mangled name{}", - mangled)); - } - - Ok(()) - } -} - -impl ClangSubItemParser for Var { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - use cexpr::expr::EvalResult; - use cexpr::literal::CChar; - match cursor.kind() { - CXCursor_MacroDefinition => { - - if let Some(visitor) = ctx.parse_callbacks() { - visitor.parsed_macro(&cursor.spelling()); - } - - let value = parse_macro(ctx, &cursor, ctx.translation_unit()); - - let (id, value) = match value { - Some(v) => v, - None => return Err(ParseError::Continue), - }; - - assert!(!id.is_empty(), "Empty macro name?"); - - let previously_defined = ctx.parsed_macro(&id); - - // NB: It's important to "note" the macro even if the result is - // not an integer, otherwise we might loose other kind of - // derived macros. - ctx.note_parsed_macro(id.clone(), value.clone()); - - if previously_defined { - let name = String::from_utf8(id).unwrap(); - warn!("Duplicated macro definition: {}", name); - return Err(ParseError::Continue); - } - - // NOTE: Unwrapping, here and above, is safe, because the - // identifier of a token comes straight from clang, and we - // enforce utf8 there, so we should have already panicked at - // this point. - let name = String::from_utf8(id).unwrap(); - let (type_kind, val) = match value { - EvalResult::Invalid => return Err(ParseError::Continue), - EvalResult::Float(f) => { - (TypeKind::Float(FloatKind::Double), VarType::Float(f)) - } - EvalResult::Char(c) => { - let c = match c { - CChar::Char(c) => { - assert_eq!(c.len_utf8(), 1); - c as u8 - } - CChar::Raw(c) => { - assert!(c <= ::std::u8::MAX as u64); - c as u8 - } - }; - - (TypeKind::Int(IntKind::U8), VarType::Char(c)) - } - EvalResult::Str(val) => { - let char_ty = - Item::builtin_type(TypeKind::Int(IntKind::U8), - true, - ctx); - (TypeKind::Pointer(char_ty), VarType::String(val)) - } - EvalResult::Int(Wrapping(value)) => { - let kind = ctx.parse_callbacks() - .and_then(|c| c.int_macro(&name, value)) - .unwrap_or_else(|| if value < 0 { - if value < i32::min_value() as i64 { - IntKind::LongLong - } else { - IntKind::Int - } - } else if value > u32::max_value() as i64 { - IntKind::ULongLong - } else { - IntKind::UInt - }); - - (TypeKind::Int(kind), VarType::Int(value)) - } - }; - - let ty = Item::builtin_type(type_kind, true, ctx); - - Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), - Some(cursor))) - } - CXCursor_VarDecl => { - let name = cursor.spelling(); - if name.is_empty() { - warn!("Empty constant name?"); - return Err(ParseError::Continue); - } - - let ty = cursor.cur_type(); - - // XXX this is redundant, remove! - let is_const = ty.is_const(); - - let ty = match Item::from_ty(&ty, cursor, None, ctx) { - Ok(ty) => ty, - Err(e) => { - assert_eq!(ty.kind(), - CXType_Auto, - "Couldn't resolve constant type, and it \ - wasn't an nondeductible auto type!"); - return Err(e); - } - }; - - // Note: Ty might not be totally resolved yet, see - // tests/headers/inner_const.hpp - // - // That's fine because in that case we know it's not a literal. - let canonical_ty = ctx.safe_resolve_type(ty) - .and_then(|t| t.safe_canonical_type(ctx)); - - let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); - let is_float = canonical_ty.map_or(false, |t| t.is_float()); - - // TODO: We could handle `char` more gracefully. - // TODO: Strings, though the lookup is a bit more hard (we need - // to look at the canonical type of the pointee too, and check - // is char, u8, or i8 I guess). - let value = if is_integer { - let kind = match *canonical_ty.unwrap().kind() { - TypeKind::Int(kind) => kind, - _ => unreachable!(), - }; - - let mut val = cursor.evaluate() - .and_then(|v| v.as_int()) - .map(|val| val as i64); - if val.is_none() || !kind.signedness_matches(val.unwrap()) { - let tu = ctx.translation_unit(); - val = get_integer_literal_from_cursor(&cursor, tu); - } - - val.map(|val| if kind == IntKind::Bool { - VarType::Bool(val != 0) - } else { - VarType::Int(val) - }) - } else if is_float { - cursor.evaluate() - .and_then(|v| v.as_double()) - .map(VarType::Float) - } else { - cursor.evaluate() - .and_then(|v| v.as_literal_string()) - .map(VarType::String) - }; - - let mangling = cursor_mangling(ctx, &cursor); - let var = Var::new(name, mangling, ty, value, is_const); - - Ok(ParseResult::New(var, Some(cursor))) - } - _ => { - /* TODO */ - Err(ParseError::Continue) - } - } - } -} - -/// Try and parse a macro using all the macros parsed until now. -fn parse_macro(ctx: &BindgenContext, - cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option<(Vec, cexpr::expr::EvalResult)> { - use cexpr::{expr, nom}; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - let parser = expr::IdentifierParser::new(ctx.parsed_macros()); - let result = parser.macro_definition(&cexpr_tokens); - - match result { - nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), - _ => None, - } -} - -fn parse_int_literal_tokens(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use cexpr::{expr, nom}; - use cexpr::expr::EvalResult; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - // TODO(emilio): We can try to parse other kinds of literals. - match expr::expr(&cexpr_tokens) { - nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), - _ => None, - } -} - -fn get_integer_literal_from_cursor(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use clang_sys::*; - let mut value = None; - cursor.visit(|c| { - match c.kind() { - CXCursor_IntegerLiteral | - CXCursor_UnaryOperator => { - value = parse_int_literal_tokens(&c, unit); - } - CXCursor_UnexposedExpr => { - value = get_integer_literal_from_cursor(&c, unit); - } - _ => (), - } - if value.is_some() { - CXChildVisit_Break - } else { - CXChildVisit_Continue - } - }); - value -} diff --git a/src/main.rs b/src/main.rs index 2ba2b1394a..5338f574fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,12 +22,12 @@ use options::builder_from_flags; pub fn main() { #[cfg(feature="logging")] log::set_logger(|max_log_level| { - use env_logger::Logger; - let env_logger = Logger::new(); - max_log_level.set(env_logger.filter()); - Box::new(env_logger) - }) - .expect("Failed to set logger."); + use env_logger::Logger; + let env_logger = Logger::new(); + max_log_level.set(env_logger.filter()); + Box::new(env_logger) + }) + .expect("Failed to set logger."); let bind_args: Vec<_> = env::args().collect(); @@ -52,8 +52,8 @@ pub fn main() { Ok((builder, output, verbose)) => { let builder_result = panic::catch_unwind(|| { - builder.generate().expect("Unable to generate bindings") - }); + builder.generate().expect("Unable to generate bindings") + }); if builder_result.is_err() { if verbose { @@ -63,9 +63,9 @@ pub fn main() { } let mut bindings = builder_result.unwrap(); - bindings.write(output) - .expect("Unable to write output"); - bindings.write_dummy_uses() + bindings.write(output).expect("Unable to write output"); + bindings + .write_dummy_uses() .expect("Unable to write dummy uses to file."); } Err(error) => { diff --git a/src/options.rs b/src/options.rs index 9072abd820..4948d0fdcf 100644 --- a/src/options.rs +++ b/src/options.rs @@ -7,7 +7,7 @@ use std::io::{self, Error, ErrorKind}; pub fn builder_from_flags (args: I) -> Result<(Builder, Box, bool), io::Error> - where I: Iterator, + where I: Iterator { let matches = App::new("bindgen") .version(env!("CARGO_PKG_VERSION")) diff --git a/tests/stylo_sanity.rs b/tests/stylo_sanity.rs index d925cb33c0..e5bfd1c219 100755 --- a/tests/stylo_sanity.rs +++ b/tests/stylo_sanity.rs @@ -539,7 +539,8 @@ fn sanity_check_can_generate_stylo_bindings() { println!(""); println!(""); - println!("Generated Stylo bindings in: {:?}", now.duration_since(then)); + println!("Generated Stylo bindings in: {:?}", + now.duration_since(then)); println!(""); println!(""); diff --git a/tests/tests.rs b/tests/tests.rs index bb965bd7ba..8b017b54c8 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -15,8 +15,11 @@ use options::builder_from_flags; fn compare_generated_header(header: &PathBuf, builder: Builder) -> Result<(), Error> { - let file_name = try!(header.file_name() - .ok_or(Error::new(ErrorKind::Other, "spawn_bindgen expects a file"))); + let file_name = + try!(header + .file_name() + .ok_or(Error::new(ErrorKind::Other, + "spawn_bindgen expects a file"))); let mut expected = PathBuf::from(header); expected.pop(); @@ -88,7 +91,8 @@ fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { return Ok(None); } else if line.contains("bindgen-osx-only") { let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; - flags = prepend_flags.into_iter() + flags = prepend_flags + .into_iter() .map(ToString::to_string) .chain(flags) .collect(); @@ -100,8 +104,10 @@ fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { // - add header filename as 1st element // - prepend raw lines so they're in the right order for expected output // - append the test header's bindgen flags - let header_str = try!(header.to_str() - .ok_or(Error::new(ErrorKind::Other, "Invalid header file name"))); + let header_str = try!(header + .to_str() + .ok_or(Error::new(ErrorKind::Other, + "Invalid header file name"))); let prepend = ["bindgen", "--with-derive-default", @@ -113,12 +119,14 @@ fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { "--raw-line", ""]; - let args = prepend.into_iter() + let args = prepend + .into_iter() .map(ToString::to_string) .chain(flags.into_iter()); - builder_from_flags(args) - .map(|(builder, _, _)| Some(builder.no_unstable_rust())) + builder_from_flags(args).map(|(builder, _, _)| { + Some(builder.no_unstable_rust()) + }) } macro_rules! test_header { @@ -153,7 +161,8 @@ fn test_header_contents() { .generate() .unwrap() .to_string(); - assert_eq!(bindings, "/* automatically generated by rust-bindgen */ + assert_eq!(bindings, + "/* automatically generated by rust-bindgen */ extern \"C\" { pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; From 9681c4bc34a778eab51db445df797a3d93385823 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 10:22:14 -0400 Subject: [PATCH 03/18] commit more changes --- bindgen-integration/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index fe7ffb1fb7..b715486c52 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -32,9 +32,7 @@ fn main() { .enable_cxx_namespaces() .raw_line("pub use self::root::*;") .header("cpp/Test.h") - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("-std=c++11") + .clang_args(&["-x", "c++", "-std=c++11"]) .parse_callbacks(Box::new(MacroCallback {macros: macros.clone()})) .generate() .expect("Unable to generate bindings"); From cd0292b7d52121d6980b7689e524788a3d543d6f Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 16:34:50 -0400 Subject: [PATCH 04/18] ignore mybuild --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 71a7df6d78..a0939325b1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ target/ bindgen-integration/Cargo.lock tests/expectations/Cargo.lock #*# +bindgen-integration/mybuild.rs From fc17cd0e372ae39295c64965c62401ab334f82a2 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 17:10:01 -0400 Subject: [PATCH 05/18] updated ir modules and tests --- src/ir/mod.rs | 23 + src/ir/module.rs | 91 ++++ src/ir/objc.rs | 254 ++++++++++ src/ir/traversal.rs | 476 ++++++++++++++++++ src/ir/var.rs | 342 +++++++++++++ .../tests/default-template-parameter.rs | 2 + ...issue-584-stylo-template-analysis-panic.rs | 1 + 7 files changed, 1189 insertions(+) create mode 100644 src/ir/mod.rs create mode 100644 src/ir/module.rs create mode 100644 src/ir/objc.rs create mode 100644 src/ir/traversal.rs create mode 100644 src/ir/var.rs diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 0000000000..d703e53dbb --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,23 @@ +//! The ir module defines bindgen's intermediate representation. +//! +//! Parsing C/C++ generates the IR, while code generation outputs Rust code from +//! the IR. + +pub mod annotations; +pub mod comp; +pub mod context; +pub mod derive; +pub mod dot; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod named; +pub mod template; +pub mod traversal; +pub mod ty; +pub mod var; +pub mod objc; diff --git a/src/ir/module.rs b/src/ir/module.rs new file mode 100644 index 0000000000..ee3912c5f1 --- /dev/null +++ b/src/ir/module.rs @@ -0,0 +1,91 @@ +//! Intermediate representation for modules (AKA C++ namespaces). + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; +use std::io; + +/// Whether this module is inline or not. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ModuleKind { + /// This module is not inline. + Normal, + /// This module is inline, as in `inline namespace foo {}`. + Inline, +} + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option, + /// The kind of module this is. + kind: ModuleKind, + /// The children of this module, just here for convenience. + children_ids: Vec, +} + +impl Module { + /// Construct a new `Module`. + pub fn new(name: Option, kind: ModuleKind) -> Self { + Module { + name: name, + kind: kind, + children_ids: vec![], + } + } + + /// Get this module's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get a mutable reference to this module's children. + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children_ids + } + + /// Get this module's children. + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } + + /// Whether this namespace is inline. + pub fn is_inline(&self) -> bool { + self.kind == ModuleKind::Inline + } +} + +impl DotAttributes for Module { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + writeln!(out, "ModuleKind{:?}", self.kind) + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx| { + cursor.visit(|cursor| { + parse_one(ctx, cursor, Some(module_id)) + }) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue), + } + } +} diff --git a/src/ir/objc.rs b/src/ir/objc.rs new file mode 100644 index 0000000000..3a88eef8ab --- /dev/null +++ b/src/ir/objc.rs @@ -0,0 +1,254 @@ +//! Objective C types + +use super::context::{BindgenContext, ItemId}; +use super::function::FunctionSig; +use super::traversal::{Trace, Tracer}; +use super::ty::TypeKind; +use clang; +use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCCategoryDecl; +use clang_sys::CXCursor_ObjCClassMethodDecl; +use clang_sys::CXCursor_ObjCClassRef; +use clang_sys::CXCursor_ObjCInstanceMethodDecl; +use clang_sys::CXCursor_ObjCProtocolDecl; +use clang_sys::CXCursor_ObjCProtocolRef; + +/// Objective C interface as used in TypeKind +/// +/// Also protocols and categories are parsed as this type +#[derive(Debug)] +pub struct ObjCInterface { + /// The name + /// like, NSObject + name: String, + + category: Option, + + is_protocol: bool, + + conforms_to: Vec, + + /// List of the methods defined in this interfae + methods: Vec, + + class_methods: Vec, +} + +/// The objective c methods +#[derive(Debug)] +pub struct ObjCMethod { + /// The original method selector name + /// like, dataWithBytes:length: + name: String, + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + rust_name: String, + + signature: FunctionSig, + + /// Is class method? + is_class_method: bool, +} + +impl ObjCInterface { + fn new(name: &str) -> ObjCInterface { + ObjCInterface { + name: name.to_owned(), + category: None, + is_protocol: false, + conforms_to: Vec::new(), + methods: Vec::new(), + class_methods: Vec::new(), + } + } + + /// The name + /// like, NSObject + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + /// and protocols are like protocol_NSObject + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + if self.is_protocol { + format!("protocol_{}", self.name()) + } else { + self.name().to_owned() + } + } + } + + /// List of the methods defined in this interface + pub fn methods(&self) -> &Vec { + &self.methods + } + + /// List of the class methods defined in this interface + pub fn class_methods(&self) -> &Vec { + &self.class_methods + } + + /// Parses the Objective C interface from the cursor + pub fn from_ty(cursor: &clang::Cursor, + ctx: &mut BindgenContext) + -> Option { + let name = cursor.spelling(); + let mut interface = Self::new(&name); + + if cursor.kind() == CXCursor_ObjCProtocolDecl { + interface.is_protocol = true; + } + + cursor.visit(|c| { + match c.kind() { + CXCursor_ObjCClassRef => { + if cursor.kind() == CXCursor_ObjCCategoryDecl { + // We are actually a category extension, and we found the reference + // to the original interface, so name this interface approriately + interface.name = c.spelling(); + interface.category = Some(cursor.spelling()); + } + } + CXCursor_ObjCProtocolRef => { + // Gather protocols this interface conforms to + let needle = format!("protocol_{}", c.spelling()); + let items_map = ctx.items(); + debug!("Interface {} conforms to {}, find the item", interface.name, needle); + + for (id, item) in items_map + { + if let Some(ty) = item.as_type() { + match *ty.kind() { + TypeKind::ObjCInterface(ref protocol) => { + if protocol.is_protocol + { + debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); + if Some(needle.as_ref()) == ty.name() + { + debug!("Found conforming protocol {:?}", item); + interface.conforms_to.push(*id); + break; + } + } + } + _ => {} + } + } + } + + } + CXCursor_ObjCInstanceMethodDecl | + CXCursor_ObjCClassMethodDecl => { + let name = c.spelling(); + let signature = + FunctionSig::from_ty(&c.cur_type(), &c, ctx) + .expect("Invalid function sig"); + let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; + let method = ObjCMethod::new(&name, signature, is_class_method); + interface.add_method(method); + } + _ => {} + } + CXChildVisit_Continue + }); + Some(interface) + } + + fn add_method(&mut self, method: ObjCMethod) { + if method.is_class_method { + self.class_methods.push(method); + } else { + self.methods.push(method); + } + } +} + +impl ObjCMethod { + fn new(name: &str, + signature: FunctionSig, + is_class_method: bool) + -> ObjCMethod { + let split_name: Vec<&str> = name.split(':').collect(); + + let rust_name = split_name.join("_"); + + ObjCMethod { + name: name.to_owned(), + rust_name: rust_name.to_owned(), + signature: signature, + is_class_method: is_class_method, + } + } + + /// The original method selector name + /// like, dataWithBytes:length: + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + pub fn rust_name(&self) -> &str { + self.rust_name.as_ref() + } + + /// Returns the methods signature as FunctionSig + pub fn signature(&self) -> &FunctionSig { + &self.signature + } + + /// Is this a class method? + pub fn is_class_method(&self) -> bool { + self.is_class_method + } + + /// Formats the method call + pub fn format_method_call(&self, args: &[String]) -> String { + let split_name: Vec<&str> = + self.name.split(':').filter(|p| !p.is_empty()).collect(); + + // No arguments + if args.len() == 0 && split_name.len() == 1 { + return split_name[0].to_string(); + } + + // Check right amount of arguments + if args.len() != split_name.len() { + panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", + args, + split_name); + } + + split_name.iter() + .zip(args.iter()) + .map(|parts| format!("{}:{} ", parts.0, parts.1)) + .collect::>() + .join("") + } +} + +impl Trace for ObjCInterface { + type Extra = (); + + fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) + where T: Tracer, + { + for method in &self.methods { + method.signature.trace(context, tracer, &()); + } + + for class_method in &self.class_methods { + class_method.signature.trace(context, tracer, &()); + } + + for protocol in &self.conforms_to { + tracer.visit(*protocol); + } + } +} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs new file mode 100644 index 0000000000..95d2a45675 --- /dev/null +++ b/src/ir/traversal.rs @@ -0,0 +1,476 @@ +//! Traversal of the graph of IR items and types. + +use super::context::{BindgenContext, ItemId}; +use super::item::ItemSet; +use std::collections::{BTreeMap, VecDeque}; + +/// An outgoing edge in the IR graph is a reference from some item to another +/// item: +/// +/// from --> to +/// +/// The `from` is left implicit: it is the concrete `Trace` implementor which +/// yielded this outgoing edge. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Edge { + to: ItemId, + kind: EdgeKind, +} + +impl Edge { + /// Construct a new edge whose referent is `to` and is of the given `kind`. + pub fn new(to: ItemId, kind: EdgeKind) -> Edge { + Edge { + to: to, + kind: kind, + } + } + + /// Get the item that this edge is pointing to. + pub fn to(&self) -> ItemId { + self.to + } + + /// Get the kind of edge that this is. + pub fn kind(&self) -> EdgeKind { + self.kind + } +} + +impl Into for Edge { + fn into(self) -> ItemId { + self.to + } +} + +/// The kind of edge reference. This is useful when we wish to only consider +/// certain kinds of edges for a particular traversal or analysis. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EdgeKind { + /// A generic, catch-all edge. + Generic, + + /// An edge from a template declaration, to the definition of a named type + /// parameter. For example, the edge from `Foo` to `T` in the following + /// snippet: + /// + /// ```C++ + /// template + /// class Foo { }; + /// ``` + TemplateParameterDefinition, + + /// An edge from a template instantiation to the template declaration that + /// is being instantiated. For example, the edge from `Foo` to + /// to `Foo`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// using Bar = Foo; + /// ``` + TemplateDeclaration, + + /// An edge from a template instantiation to its template argument. For + /// example, `Foo` to `Bar`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// class Bar { }; + /// + /// using FooBar = Foo; + /// ``` + TemplateArgument, + + /// An edge from a compound type to one of its base member types. For + /// example, the edge from `Bar` to `Foo`: + /// + /// ```C++ + /// class Foo { }; + /// + /// class Bar : public Foo { }; + /// ``` + BaseMember, + + /// An edge from a compound type to the types of one of its fields. For + /// example, the edge from `Foo` to `int`: + /// + /// ```C++ + /// class Foo { + /// int x; + /// }; + /// ``` + Field, + + /// An edge from an class or struct type to an inner type member. For + /// example, the edge from `Foo` to `Foo::Bar` here: + /// + /// ```C++ + /// class Foo { + /// struct Bar { }; + /// }; + /// ``` + InnerType, + + /// An edge from an class or struct type to an inner static variable. For + /// example, the edge from `Foo` to `Foo::BAR` here: + /// + /// ```C++ + /// class Foo { + /// static const char* BAR; + /// }; + /// ``` + InnerVar, + + /// An edge from a class or struct type to one of its method functions. For + /// example, the edge from `Foo` to `Foo::bar`: + /// + /// ```C++ + /// class Foo { + /// bool bar(int x, int y); + /// }; + /// ``` + Method, + + /// An edge from a class or struct type to one of its constructor + /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: + /// + /// ```C++ + /// class Foo { + /// int my_x; + /// int my_y; + /// + /// public: + /// Foo(int x, int y); + /// }; + /// ``` + Constructor, + + /// An edge from a function declaration to its return type. For example, the + /// edge from `foo` to `int`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionReturn, + + /// An edge from a function declaration to one of its parameter types. For + /// example, the edge from `foo` to `char*`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionParameter, + + /// An edge from a static variable to its type. For example, the edge from + /// `FOO` to `const char*`: + /// + /// ```C++ + /// static const char* FOO; + /// ``` + VarType, + + /// An edge from a non-templated alias or typedef to the referenced type. + TypeReference, +} + +/// A predicate to allow visiting only sub-sets of the whole IR graph by +/// excluding certain edges from being followed by the traversal. +pub trait TraversalPredicate { + /// Should the traversal follow this edge, and visit everything that is + /// reachable through it? + fn should_follow(&self, edge: Edge) -> bool; +} + +impl TraversalPredicate for fn(Edge) -> bool { + fn should_follow(&self, edge: Edge) -> bool { + (*self)(edge) + } +} + +/// A `TraversalPredicate` implementation that follows all edges, and therefore +/// traversals using this predicate will see the whole IR graph reachable from +/// the traversal's roots. +pub fn all_edges(_: Edge) -> bool { + true +} + +/// A `TraversalPredicate` implementation that never follows any edges, and +/// therefore traversals using this predicate will only visit the traversal's +/// roots. +pub fn no_edges(_: Edge) -> bool { + false +} + +/// The storage for the set of items that have been seen (although their +/// outgoing edges might not have been fully traversed yet) in an active +/// traversal. +pub trait TraversalStorage<'ctx, 'gen> { + /// Construct a new instance of this TraversalStorage, for a new traversal. + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; + + /// Add the given item to the storage. If the item has never been seen + /// before, return `true`. Otherwise, return `false`. + /// + /// The `from` item is the item from which we discovered this item, or is + /// `None` if this item is a root. + fn add(&mut self, from: Option, item: ItemId) -> bool; +} + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { + fn new(_: &'ctx BindgenContext<'gen>) -> Self { + ItemSet::new() + } + + fn add(&mut self, _: Option, item: ItemId) -> bool { + self.insert(item) + } +} + +/// A `TraversalStorage` implementation that keeps track of how we first reached +/// each item. This is useful for providing debug assertions with meaningful +/// diagnostic messages about dangling items. +#[derive(Debug)] +pub struct Paths<'ctx, 'gen>(BTreeMap, + &'ctx BindgenContext<'gen>) + where 'gen: 'ctx; + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> + where 'gen: 'ctx, +{ + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { + Paths(BTreeMap::new(), ctx) + } + + fn add(&mut self, from: Option, item: ItemId) -> bool { + let newly_discovered = + self.0.insert(item, from.unwrap_or(item)).is_none(); + + if self.1.resolve_item_fallible(item).is_none() { + let mut path = vec![]; + let mut current = item; + loop { + let predecessor = *self.0 + .get(¤t) + .expect("We know we found this item id, so it must have a \ + predecessor"); + if predecessor == current { + break; + } + path.push(predecessor); + current = predecessor; + } + path.reverse(); + panic!("Found reference to dangling id = {:?}\nvia path = {:?}", + item, + path); + } + + newly_discovered + } +} + +/// The queue of seen-but-not-yet-traversed items. +/// +/// Using a FIFO queue with a traversal will yield a breadth-first traversal, +/// while using a LIFO queue will result in a depth-first traversal of the IR +/// graph. +pub trait TraversalQueue: Default { + /// Add a newly discovered item to the queue. + fn push(&mut self, item: ItemId); + + /// Pop the next item to traverse, if any. + fn next(&mut self) -> Option; +} + +impl TraversalQueue for Vec { + fn push(&mut self, item: ItemId) { + self.push(item); + } + + fn next(&mut self) -> Option { + self.pop() + } +} + +impl TraversalQueue for VecDeque { + fn push(&mut self, item: ItemId) { + self.push_back(item); + } + + fn next(&mut self) -> Option { + self.pop_front() + } +} + +/// Something that can receive edges from a `Trace` implementation. +pub trait Tracer { + /// Note an edge between items. Called from within a `Trace` implementation. + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); + + /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. + fn visit(&mut self, item: ItemId) { + self.visit_kind(item, EdgeKind::Generic); + } +} + +impl Tracer for F + where F: FnMut(ItemId, EdgeKind), +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + (*self)(item, kind) + } +} + +/// Trace all of the outgoing edges to other items. Implementations should call +/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` +/// for each of their outgoing edges. +pub trait Trace { + /// If a particular type needs extra information beyond what it has in + /// `self` and `context` to find its referenced items, its implementation + /// can define this associated type, forcing callers to pass the needed + /// information through. + type Extra; + + /// Trace all of this item's outgoing edges to other items. + fn trace(&self, + context: &BindgenContext, + tracer: &mut T, + extra: &Self::Extra) + where T: Tracer; +} + +/// An graph traversal of the transitive closure of references between items. +/// +/// See `BindgenContext::whitelisted_items` for more information. +pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + ctx: &'ctx BindgenContext<'gen>, + + /// The set of items we have seen thus far in this traversal. + seen: Storage, + + /// The set of items that we have seen, but have yet to traverse. + queue: Queue, + + /// The predicate that determins which edges this traversal will follow. + predicate: Predicate, + + /// The item we are currently traversing. + currently_traversing: Option, +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, + 'gen, + Storage, + Queue, + Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + /// Begin a new traversal, starting from the given roots. + pub fn new(ctx: &'ctx BindgenContext<'gen>, + roots: R, + predicate: Predicate) + -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where R: IntoIterator, + { + let mut seen = Storage::new(ctx); + let mut queue = Queue::default(); + + for id in roots { + seen.add(None, id); + queue.push(id); + } + + ItemTraversal { + ctx: ctx, + seen: seen, + queue: queue, + predicate: predicate, + currently_traversing: None, + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + let edge = Edge::new(item, kind); + if !self.predicate.should_follow(edge) { + return; + } + + let is_newly_discovered = self.seen + .add(self.currently_traversing, item); + if is_newly_discovered { + self.queue.push(item) + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + type Item = ItemId; + + fn next(&mut self) -> Option { + let id = match self.queue.next() { + None => return None, + Some(id) => id, + }; + + let newly_discovered = self.seen.add(None, id); + debug_assert!(!newly_discovered, + "should have already seen anything we get out of our queue"); + debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), + "should only get IDs of actual items in our context during traversal"); + + self.currently_traversing = Some(id); + id.trace(self.ctx, self, &()); + self.currently_traversing = None; + + Some(id) + } +} + +/// An iterator to find any dangling items. +/// +/// See `BindgenContext::assert_no_dangling_item_traversal` for more +/// information. +pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = + ItemTraversal<'ctx, + 'gen, + Paths<'ctx, 'gen>, + VecDeque, + fn(Edge) -> bool>; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(dead_code)] + fn traversal_predicate_is_object_safe() { + // This should compile only if TraversalPredicate is object safe. + fn takes_by_trait_object(_: &TraversalPredicate) {} + } +} diff --git a/src/ir/var.rs b/src/ir/var.rs new file mode 100644 index 0000000000..656a1a6dfd --- /dev/null +++ b/src/ir/var.rs @@ -0,0 +1,342 @@ +//! Intermediate representation of variables. + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use super::function::cursor_mangling; +use super::int::IntKind; +use super::item::Item; +use super::ty::{FloatKind, TypeKind}; +use cexpr; +use clang; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; +use std::num::Wrapping; + +/// The type for a constant variable. +#[derive(Debug)] +pub enum VarType { + /// A boolean. + Bool(bool), + /// An integer. + Int(i64), + /// A floating point number. + Float(f64), + /// A character. + Char(u8), + /// A string, not necessarily well-formed utf-8. + String(Vec), +} + +/// A `Var` is our intermediate representation of a variable. +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option, + /// The type of the variable. + ty: ItemId, + /// The value of the variable, that needs to be suitable for `ty`. + val: Option, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + /// Construct a new `Var`. + pub fn new(name: String, + mangled: Option, + ty: ItemId, + val: Option, + is_const: bool) + -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + /// Is this variable `const` qualified? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// The value of this constant variable, if any. + pub fn val(&self) -> Option<&VarType> { + self.val.as_ref() + } + + /// Get this variable's type. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get this variable's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variable's mangled name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl DotAttributes for Var { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + if self.is_const { + try!(writeln!(out, "consttrue")); + } + + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, + "mangled name{}", + mangled)); + } + + Ok(()) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + use cexpr::expr::EvalResult; + use cexpr::literal::CChar; + match cursor.kind() { + CXCursor_MacroDefinition => { + + if let Some(visitor) = ctx.parse_callbacks() { + visitor.parsed_macro(&cursor.spelling()); + } + + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); + + let (id, value) = match value { + Some(v) => v, + None => return Err(ParseError::Continue), + }; + + assert!(!id.is_empty(), "Empty macro name?"); + + let previously_defined = ctx.parsed_macro(&id); + + // NB: It's important to "note" the macro even if the result is + // not an integer, otherwise we might loose other kind of + // derived macros. + ctx.note_parsed_macro(id.clone(), value.clone()); + + if previously_defined { + let name = String::from_utf8(id).unwrap(); + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + + // NOTE: Unwrapping, here and above, is safe, because the + // identifier of a token comes straight from clang, and we + // enforce utf8 there, so we should have already panicked at + // this point. + let name = String::from_utf8(id).unwrap(); + let (type_kind, val) = match value { + EvalResult::Invalid => return Err(ParseError::Continue), + EvalResult::Float(f) => { + (TypeKind::Float(FloatKind::Double), VarType::Float(f)) + } + EvalResult::Char(c) => { + let c = match c { + CChar::Char(c) => { + assert_eq!(c.len_utf8(), 1); + c as u8 + } + CChar::Raw(c) => { + assert!(c <= ::std::u8::MAX as u64); + c as u8 + } + }; + + (TypeKind::Int(IntKind::U8), VarType::Char(c)) + } + EvalResult::Str(val) => { + let char_ty = + Item::builtin_type(TypeKind::Int(IntKind::U8), + true, + ctx); + (TypeKind::Pointer(char_ty), VarType::String(val)) + } + EvalResult::Int(Wrapping(value)) => { + let kind = ctx.parse_callbacks() + .and_then(|c| c.int_macro(&name, value)) + .unwrap_or_else(|| if value < 0 { + if value < i32::min_value() as i64 { + IntKind::LongLong + } else { + IntKind::Int + } + } else if value > u32::max_value() as i64 { + IntKind::ULongLong + } else { + IntKind::UInt + }); + + (TypeKind::Int(kind), VarType::Int(value)) + } + }; + + let ty = Item::builtin_type(type_kind, true, ctx); + + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), + Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = match Item::from_ty(&ty, cursor, None, ctx) { + Ok(ty) => ty, + Err(e) => { + assert_eq!(ty.kind(), + CXType_Auto, + "Couldn't resolve constant type, and it \ + wasn't an nondeductible auto type!"); + return Err(e); + } + }; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + let canonical_ty = ctx.safe_resolve_type(ty) + .and_then(|t| t.safe_canonical_type(ctx)); + + let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); + let is_float = canonical_ty.map_or(false, |t| t.is_float()); + + // TODO: We could handle `char` more gracefully. + // TODO: Strings, though the lookup is a bit more hard (we need + // to look at the canonical type of the pointee too, and check + // is char, u8, or i8 I guess). + let value = if is_integer { + let kind = match *canonical_ty.unwrap().kind() { + TypeKind::Int(kind) => kind, + _ => unreachable!(), + }; + + let mut val = cursor.evaluate() + .and_then(|v| v.as_int()) + .map(|val| val as i64); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { + let tu = ctx.translation_unit(); + val = get_integer_literal_from_cursor(&cursor, tu); + } + + val.map(|val| if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + }) + } else if is_float { + cursor.evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float) + } else { + cursor.evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String) + }; + + let mangling = cursor_mangling(ctx, &cursor); + let var = Var::new(name, mangling, ty, value, is_const); + + Ok(ParseResult::New(var, Some(cursor))) + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +/// Try and parse a macro using all the macros parsed until now. +fn parse_macro(ctx: &BindgenContext, + cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<(Vec, cexpr::expr::EvalResult)> { + use cexpr::{expr, nom}; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); + let result = parser.macro_definition(&cexpr_tokens); + + match result { + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), + _ => None, + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use cexpr::{expr, nom}; + use cexpr::expr::EvalResult; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + // TODO(emilio): We can try to parse other kinds of literals. + match expr::expr(&cexpr_tokens) { + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), + _ => None, + } +} + +fn get_integer_literal_from_cursor(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use clang_sys::*; + let mut value = None; + cursor.visit(|c| { + match c.kind() { + CXCursor_IntegerLiteral | + CXCursor_UnaryOperator => { + value = parse_int_literal_tokens(&c, unit); + } + CXCursor_UnexposedExpr => { + value = get_integer_literal_from_cursor(&c, unit); + } + _ => (), + } + if value.is_some() { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + value +} diff --git a/tests/expectations/tests/default-template-parameter.rs b/tests/expectations/tests/default-template-parameter.rs index af4616ff9b..c098dac7b5 100644 --- a/tests/expectations/tests/default-template-parameter.rs +++ b/tests/expectations/tests/default-template-parameter.rs @@ -9,6 +9,8 @@ pub struct Foo { pub t: T, pub u: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs index 91b8e49a16..ddcaf3fc0b 100644 --- a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs +++ b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs @@ -43,6 +43,7 @@ impl Clone for A { #[derive(Debug, Copy, Clone)] pub struct e { pub d: RefPtr, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for e { fn default() -> Self { unsafe { ::std::mem::zeroed() } } From b01ccd19f0e86eda577e44a576fae04bbc1b9ee9 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 17:17:20 -0400 Subject: [PATCH 06/18] housekeeping --- .gitignore | 2 ++ build.rs | 31 ++++++++++++++----------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index a0939325b1..91a6101e62 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ bindgen-integration/Cargo.lock tests/expectations/Cargo.lock #*# bindgen-integration/mybuild.rs +ir.dot +ir.png diff --git a/build.rs b/build.rs index e299a671e3..bda91e28ac 100644 --- a/build.rs +++ b/build.rs @@ -26,34 +26,31 @@ mod testgen { pub fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut dst = File::create(Path::new(&out_dir).join("tests.rs")) - .unwrap(); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); - println!("cargo:rerun-if-changed=tests/headers"); - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR") - .unwrap()); + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let headers_dir = manifest_dir.join("tests").join("headers"); + let headers = match fs::read_dir(headers_dir) { + Ok(dir) => dir, + // We may not have headers directory after packaging. + Err(..) => return, + }; + let entries = - fs::read_dir(headers_dir) - .expect("Couldn't read headers dir") - .map(|result| result.expect("Couldn't read header file")); + headers.map(|result| result.expect("Couldn't read header file")); + + println!("cargo:rerun-if-changed=tests/headers"); for entry in entries { match entry.path().extension().and_then(OsStr::to_str) { Some("h") | Some("hpp") => { - let func = entry - .file_name() - .to_str() - .unwrap() + let func = entry.file_name().to_str().unwrap() .replace(|c| !char::is_alphanumeric(c), "_") .replace("__", "_") .to_lowercase(); - writeln!(dst, - "test_header!(header_{}, {:?});", - func, - entry.path()) - .unwrap(); + writeln!(dst, "test_header!(header_{}, {:?});", + func, entry.path()).unwrap(); } _ => {} } From 3bb4d9179f469b3347886846930694e991e5c69b Mon Sep 17 00:00:00 2001 From: Date: Mon, 17 Apr 2017 17:21:11 -0400 Subject: [PATCH 07/18] dealing with modifications --- src/ir/annotations.rs | 376 +++++++++++++++++++++--------------------- src/ir/derive.rs | 176 ++++++++++---------- src/ir/dot.rs | 124 +++++++------- 3 files changed, 338 insertions(+), 338 deletions(-) diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs index 98be0540f2..51c4ef6325 100644 --- a/src/ir/annotations.rs +++ b/src/ir/annotations.rs @@ -1,188 +1,188 @@ -//! Types and functions related to bindgen annotation comments. -//! -//! Users can add annotations in doc comments to types that they would like to -//! replace other types with, mark as opaque, etc. This module deals with all of -//! that stuff. - -use clang; - -/// What kind of accessor should we provide for a field? -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum FieldAccessorKind { - /// No accessor. - None, - /// Plain accessor. - Regular, - /// Unsafe accessor. - Unsafe, - /// Immutable accessor. - Immutable, -} - -/// Annotations for a given item, or a field. -/// -/// You can see the kind of comments that are accepted in the Doxygen -/// documentation: -/// -/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html -#[derive(Clone, PartialEq, Debug)] -pub struct Annotations { - /// Whether this item is marked as opaque. Only applies to types. - opaque: bool, - /// Whether this item should be hidden from the output. Only applies to - /// types, or enum variants. - hide: bool, - /// Whether this type should be replaced by another. The name is a - /// namespace-aware path. - use_instead_of: Option>, - /// Manually disable deriving copy/clone on this type. Only applies to - /// struct or union types. - disallow_copy: bool, - /// Whether fields should be marked as private or not. You can set this on - /// structs (it will apply to all the fields), or individual fields. - private_fields: Option, - /// The kind of accessor this field will have. Also can be applied to - /// structs so all the fields inside share it by default. - accessor_kind: Option, - /// Whether this enum variant should be constified. - /// - /// This is controlled by the `constant` attribute, this way: - /// - /// ```cpp - /// enum Foo { - /// Bar = 0, /**<
*/ - /// Baz = 0, - /// }; - /// ``` - /// - /// In that case, bindgen will generate a constant for `Bar` instead of - /// `Baz`. - constify_enum_variant: bool, -} - -fn parse_accessor(s: &str) -> FieldAccessorKind { - match s { - "false" => FieldAccessorKind::None, - "unsafe" => FieldAccessorKind::Unsafe, - "immutable" => FieldAccessorKind::Immutable, - _ => FieldAccessorKind::Regular, - } -} - -impl Default for Annotations { - fn default() -> Self { - Annotations { - opaque: false, - hide: false, - use_instead_of: None, - disallow_copy: false, - private_fields: None, - accessor_kind: None, - constify_enum_variant: false, - } - } -} - -impl Annotations { - /// Construct new annotations for the given cursor and its bindgen comments - /// (if any). - pub fn new(cursor: &clang::Cursor) -> Option { - let mut anno = Annotations::default(); - let mut matched_one = false; - anno.parse(&cursor.comment(), &mut matched_one); - - if matched_one { Some(anno) } else { None } - } - - /// Should this type be hidden? - pub fn hide(&self) -> bool { - self.hide - } - - /// Should this type be opaque? - pub fn opaque(&self) -> bool { - self.opaque - } - - /// For a given type, indicates the type it should replace. - /// - /// For example, in the following code: - /// - /// ```cpp - /// - /// /**
*/ - /// struct Foo { int x; }; - /// - /// struct Bar { char foo; }; - /// ``` - /// - /// the generated code would look something like: - /// - /// ``` - /// /**
*/ - /// struct Bar { - /// x: ::std::os::raw::c_int, - /// }; - /// ``` - /// - /// That is, code for `Foo` is used to generate `Bar`. - pub fn use_instead_of(&self) -> Option<&[String]> { - self.use_instead_of.as_ref().map(|s| &**s) - } - - /// Should we avoid implementing the `Copy` trait? - pub fn disallow_copy(&self) -> bool { - self.disallow_copy - } - - /// Should the fields be private? - pub fn private_fields(&self) -> Option { - self.private_fields - } - - /// What kind of accessors should we provide for this type's fields? - pub fn accessor_kind(&self) -> Option { - self.accessor_kind - } - - fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { - use clang_sys::CXComment_HTMLStartTag; - if comment.kind() == CXComment_HTMLStartTag && - comment.get_tag_name() == "div" && - comment.get_tag_attrs() - .next() - .map_or(false, |attr| attr.name == "rustbindgen") { - *matched = true; - for attr in comment.get_tag_attrs() { - match attr.name.as_str() { - "opaque" => self.opaque = true, - "hide" => self.hide = true, - "nocopy" => self.disallow_copy = true, - "replaces" => { - self.use_instead_of = Some(attr.value - .split("::") - .map(Into::into) - .collect()) - } - "private" => { - self.private_fields = Some(attr.value != "false") - } - "accessor" => { - self.accessor_kind = Some(parse_accessor(&attr.value)) - } - "constant" => self.constify_enum_variant = true, - _ => {} - } - } - } - - for child in comment.get_children() { - self.parse(&child, matched); - } - } - - /// Returns whether we've parsed a "constant" attribute. - pub fn constify_enum_variant(&self) -> bool { - self.constify_enum_variant - } -} +//! Types and functions related to bindgen annotation comments. +//! +//! Users can add annotations in doc comments to types that they would like to +//! replace other types with, mark as opaque, etc. This module deals with all of +//! that stuff. + +use clang; + +/// What kind of accessor should we provide for a field? +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum FieldAccessorKind { + /// No accessor. + None, + /// Plain accessor. + Regular, + /// Unsafe accessor. + Unsafe, + /// Immutable accessor. + Immutable, +} + +/// Annotations for a given item, or a field. +/// +/// You can see the kind of comments that are accepted in the Doxygen +/// documentation: +/// +/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html +#[derive(Clone, PartialEq, Debug)] +pub struct Annotations { + /// Whether this item is marked as opaque. Only applies to types. + opaque: bool, + /// Whether this item should be hidden from the output. Only applies to + /// types, or enum variants. + hide: bool, + /// Whether this type should be replaced by another. The name is a + /// namespace-aware path. + use_instead_of: Option>, + /// Manually disable deriving copy/clone on this type. Only applies to + /// struct or union types. + disallow_copy: bool, + /// Whether fields should be marked as private or not. You can set this on + /// structs (it will apply to all the fields), or individual fields. + private_fields: Option, + /// The kind of accessor this field will have. Also can be applied to + /// structs so all the fields inside share it by default. + accessor_kind: Option, + /// Whether this enum variant should be constified. + /// + /// This is controlled by the `constant` attribute, this way: + /// + /// ```cpp + /// enum Foo { + /// Bar = 0, /**<
*/ + /// Baz = 0, + /// }; + /// ``` + /// + /// In that case, bindgen will generate a constant for `Bar` instead of + /// `Baz`. + constify_enum_variant: bool, +} + +fn parse_accessor(s: &str) -> FieldAccessorKind { + match s { + "false" => FieldAccessorKind::None, + "unsafe" => FieldAccessorKind::Unsafe, + "immutable" => FieldAccessorKind::Immutable, + _ => FieldAccessorKind::Regular, + } +} + +impl Default for Annotations { + fn default() -> Self { + Annotations { + opaque: false, + hide: false, + use_instead_of: None, + disallow_copy: false, + private_fields: None, + accessor_kind: None, + constify_enum_variant: false, + } + } +} + +impl Annotations { + /// Construct new annotations for the given cursor and its bindgen comments + /// (if any). + pub fn new(cursor: &clang::Cursor) -> Option { + let mut anno = Annotations::default(); + let mut matched_one = false; + anno.parse(&cursor.comment(), &mut matched_one); + + if matched_one { Some(anno) } else { None } + } + + /// Should this type be hidden? + pub fn hide(&self) -> bool { + self.hide + } + + /// Should this type be opaque? + pub fn opaque(&self) -> bool { + self.opaque + } + + /// For a given type, indicates the type it should replace. + /// + /// For example, in the following code: + /// + /// ```cpp + /// + /// /**
*/ + /// struct Foo { int x; }; + /// + /// struct Bar { char foo; }; + /// ``` + /// + /// the generated code would look something like: + /// + /// ``` + /// /**
*/ + /// struct Bar { + /// x: ::std::os::raw::c_int, + /// }; + /// ``` + /// + /// That is, code for `Foo` is used to generate `Bar`. + pub fn use_instead_of(&self) -> Option<&[String]> { + self.use_instead_of.as_ref().map(|s| &**s) + } + + /// Should we avoid implementing the `Copy` trait? + pub fn disallow_copy(&self) -> bool { + self.disallow_copy + } + + /// Should the fields be private? + pub fn private_fields(&self) -> Option { + self.private_fields + } + + /// What kind of accessors should we provide for this type's fields? + pub fn accessor_kind(&self) -> Option { + self.accessor_kind + } + + fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { + use clang_sys::CXComment_HTMLStartTag; + if comment.kind() == CXComment_HTMLStartTag && + comment.get_tag_name() == "div" && + comment.get_tag_attrs() + .next() + .map_or(false, |attr| attr.name == "rustbindgen") { + *matched = true; + for attr in comment.get_tag_attrs() { + match attr.name.as_str() { + "opaque" => self.opaque = true, + "hide" => self.hide = true, + "nocopy" => self.disallow_copy = true, + "replaces" => { + self.use_instead_of = Some(attr.value + .split("::") + .map(Into::into) + .collect()) + } + "private" => { + self.private_fields = Some(attr.value != "false") + } + "accessor" => { + self.accessor_kind = Some(parse_accessor(&attr.value)) + } + "constant" => self.constify_enum_variant = true, + _ => {} + } + } + } + + for child in comment.get_children() { + self.parse(&child, matched); + } + } + + /// Returns whether we've parsed a "constant" attribute. + pub fn constify_enum_variant(&self) -> bool { + self.constify_enum_variant + } +} diff --git a/src/ir/derive.rs b/src/ir/derive.rs index 0fc8debffa..6b4c766e11 100644 --- a/src/ir/derive.rs +++ b/src/ir/derive.rs @@ -1,88 +1,88 @@ -//! Traits for determining whether we can derive traits for a thing or not. - -use super::context::BindgenContext; - -/// A trait that encapsulates the logic for whether or not we can derive `Debug` -/// for a given thing. -/// -/// This should ideally be a no-op that just returns `true`, but instead needs -/// to be a recursive method that checks whether all the proper members can -/// derive debug or not, because of the limit rust has on 32 items as max in the -/// array. -pub trait CanDeriveDebug { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Debug`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Debug` can be derived for this thing, `false` - /// otherwise. - fn can_derive_debug(&self, - ctx: &BindgenContext, - extra: Self::Extra) - -> bool; -} - -/// A trait that encapsulates the logic for whether or not we can derive `Copy` -/// for a given thing. -pub trait CanDeriveCopy<'a> { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Copy`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Copy` can be derived for this thing, `false` - /// otherwise. - fn can_derive_copy(&'a self, - ctx: &'a BindgenContext, - extra: Self::Extra) - -> bool; - - /// For some reason, deriving copies of an array of a type that is not known - /// to be `Copy` is a compile error. e.g.: - /// - /// ```rust - /// #[derive(Copy, Clone)] - /// struct A { - /// member: T, - /// } - /// ``` - /// - /// is fine, while: - /// - /// ```rust,ignore - /// #[derive(Copy, Clone)] - /// struct A { - /// member: [T; 1], - /// } - /// ``` - /// - /// is an error. - /// - /// That's the whole point of the existence of `can_derive_copy_in_array`. - fn can_derive_copy_in_array(&'a self, - ctx: &'a BindgenContext, - extra: Self::Extra) - -> bool; -} - -/// A trait that encapsulates the logic for whether or not we can derive `Default` -/// for a given thing. -/// -/// This should ideally be a no-op that just returns `true`, but instead needs -/// to be a recursive method that checks whether all the proper members can -/// derive default or not, because of the limit rust has on 32 items as max in the -/// array. -pub trait CanDeriveDefault { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Default`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Default` can be derived for this thing, `false` - /// otherwise. - fn can_derive_default(&self, - ctx: &BindgenContext, - extra: Self::Extra) - -> bool; -} +//! Traits for determining whether we can derive traits for a thing or not. + +use super::context::BindgenContext; + +/// A trait that encapsulates the logic for whether or not we can derive `Debug` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive debug or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDebug { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Debug`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Debug` can be derived for this thing, `false` + /// otherwise. + fn can_derive_debug(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +} + +/// A trait that encapsulates the logic for whether or not we can derive `Copy` +/// for a given thing. +pub trait CanDeriveCopy<'a> { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Copy`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Copy` can be derived for this thing, `false` + /// otherwise. + fn can_derive_copy(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; + + /// For some reason, deriving copies of an array of a type that is not known + /// to be `Copy` is a compile error. e.g.: + /// + /// ```rust + /// #[derive(Copy, Clone)] + /// struct A { + /// member: T, + /// } + /// ``` + /// + /// is fine, while: + /// + /// ```rust,ignore + /// #[derive(Copy, Clone)] + /// struct A { + /// member: [T; 1], + /// } + /// ``` + /// + /// is an error. + /// + /// That's the whole point of the existence of `can_derive_copy_in_array`. + fn can_derive_copy_in_array(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; +} + +/// A trait that encapsulates the logic for whether or not we can derive `Default` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive default or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDefault { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Default`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Default` can be derived for this thing, `false` + /// otherwise. + fn can_derive_default(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +} diff --git a/src/ir/dot.rs b/src/ir/dot.rs index 7472dd8e0f..8a44c9025c 100644 --- a/src/ir/dot.rs +++ b/src/ir/dot.rs @@ -1,62 +1,62 @@ -//! Generating Graphviz `dot` files from our IR. - -use super::context::{BindgenContext, ItemId}; -use super::traversal::Trace; -use std::fs::File; -use std::io::{self, Write}; -use std::path::Path; - -/// A trait for anything that can write attributes as `` rows to a dot -/// file. -pub trait DotAttributes { - /// Write this thing's attributes to the given output. Each attribute must - /// be its own `...`. - fn dot_attributes(&self, - ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write; -} - -/// Write a graphviz dot file containing our IR. -pub fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> - where P: AsRef, -{ - let file = try!(File::create(path)); - let mut dot_file = io::BufWriter::new(file); - try!(writeln!(&mut dot_file, "digraph {{")); - - let mut err: Option> = None; - - for (id, item) in ctx.items() { - try!(writeln!(&mut dot_file, - r#"{} [fontname="courier", label=<

"#, - id.as_usize())); - try!(item.dot_attributes(ctx, &mut dot_file)); - try!(writeln!(&mut dot_file, r#"
>];"#)); - - item.trace(ctx, - &mut |sub_id: ItemId, edge_kind| { - if err.is_some() { - return; - } - - match writeln!(&mut dot_file, - "{} -> {} [label={:?}];", - id.as_usize(), - sub_id.as_usize(), - edge_kind) { - Ok(_) => {} - Err(e) => err = Some(Err(e)), - } - }, - &()); - - if let Some(err) = err { - return err; - } - } - - try!(writeln!(&mut dot_file, "}}")); - Ok(()) -} +//! Generating Graphviz `dot` files from our IR. + +use super::context::{BindgenContext, ItemId}; +use super::traversal::Trace; +use std::fs::File; +use std::io::{self, Write}; +use std::path::Path; + +/// A trait for anything that can write attributes as `` rows to a dot +/// file. +pub trait DotAttributes { + /// Write this thing's attributes to the given output. Each attribute must + /// be its own `...`. + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write; +} + +/// Write a graphviz dot file containing our IR. +pub fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> + where P: AsRef, +{ + let file = try!(File::create(path)); + let mut dot_file = io::BufWriter::new(file); + try!(writeln!(&mut dot_file, "digraph {{")); + + let mut err: Option> = None; + + for (id, item) in ctx.items() { + try!(writeln!(&mut dot_file, + r#"{} [fontname="courier", label=<

"#, + id.as_usize())); + try!(item.dot_attributes(ctx, &mut dot_file)); + try!(writeln!(&mut dot_file, r#"
>];"#)); + + item.trace(ctx, + &mut |sub_id: ItemId, edge_kind| { + if err.is_some() { + return; + } + + match writeln!(&mut dot_file, + "{} -> {} [label={:?}];", + id.as_usize(), + sub_id.as_usize(), + edge_kind) { + Ok(_) => {} + Err(e) => err = Some(Err(e)), + } + }, + &()); + + if let Some(err) = err { + return err; + } + } + + try!(writeln!(&mut dot_file, "}}")); + Ok(()) +} From 25e1a49f21f7707ce045f5541bc053944e6e4db8 Mon Sep 17 00:00:00 2001 From: Date: Mon, 17 Apr 2017 17:23:59 -0400 Subject: [PATCH 08/18] added ir files from servo/master --- build.rs | 132 +- src/clang.rs | 3516 +++++++++++++++++++++---------------------- src/ir/enum_ty.rs | 380 ++--- src/ir/item_kind.rs | 294 ++-- src/ir/layout.rs | 268 ++-- src/ir/mod.rs | 46 +- src/ir/module.rs | 182 +-- src/ir/objc.rs | 508 +++---- src/ir/traversal.rs | 952 ++++++------ src/ir/var.rs | 684 ++++----- 10 files changed, 3481 insertions(+), 3481 deletions(-) diff --git a/build.rs b/build.rs index bda91e28ac..86d80260df 100644 --- a/build.rs +++ b/build.rs @@ -1,66 +1,66 @@ -mod codegen { - extern crate quasi_codegen; - use std::env; - use std::path::{Path, PathBuf}; - - pub fn main() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let src = Path::new("src/codegen/mod.rs"); - let dst = Path::new(&out_dir).join("codegen.rs"); - - quasi_codegen::expand(&src, &dst).unwrap(); - println!("cargo:rerun-if-changed=src/codegen/mod.rs"); - println!("cargo:rerun-if-changed=src/codegen/error.rs"); - println!("cargo:rerun-if-changed=src/codegen/helpers.rs"); - println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs"); - } -} - -mod testgen { - use std::char; - use std::env; - use std::ffi::OsStr; - use std::fs::{self, File}; - use std::io::Write; - use std::path::{Path, PathBuf}; - - pub fn main() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); - - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let headers_dir = manifest_dir.join("tests").join("headers"); - - let headers = match fs::read_dir(headers_dir) { - Ok(dir) => dir, - // We may not have headers directory after packaging. - Err(..) => return, - }; - - let entries = - headers.map(|result| result.expect("Couldn't read header file")); - - println!("cargo:rerun-if-changed=tests/headers"); - - for entry in entries { - match entry.path().extension().and_then(OsStr::to_str) { - Some("h") | Some("hpp") => { - let func = entry.file_name().to_str().unwrap() - .replace(|c| !char::is_alphanumeric(c), "_") - .replace("__", "_") - .to_lowercase(); - writeln!(dst, "test_header!(header_{}, {:?});", - func, entry.path()).unwrap(); - } - _ => {} - } - } - - dst.flush().unwrap(); - } -} - -fn main() { - codegen::main(); - testgen::main(); -} +mod codegen { + extern crate quasi_codegen; + use std::env; + use std::path::{Path, PathBuf}; + + pub fn main() { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let src = Path::new("src/codegen/mod.rs"); + let dst = Path::new(&out_dir).join("codegen.rs"); + + quasi_codegen::expand(&src, &dst).unwrap(); + println!("cargo:rerun-if-changed=src/codegen/mod.rs"); + println!("cargo:rerun-if-changed=src/codegen/error.rs"); + println!("cargo:rerun-if-changed=src/codegen/helpers.rs"); + println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs"); + } +} + +mod testgen { + use std::char; + use std::env; + use std::ffi::OsStr; + use std::fs::{self, File}; + use std::io::Write; + use std::path::{Path, PathBuf}; + + pub fn main() { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); + + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let headers_dir = manifest_dir.join("tests").join("headers"); + + let headers = match fs::read_dir(headers_dir) { + Ok(dir) => dir, + // We may not have headers directory after packaging. + Err(..) => return, + }; + + let entries = + headers.map(|result| result.expect("Couldn't read header file")); + + println!("cargo:rerun-if-changed=tests/headers"); + + for entry in entries { + match entry.path().extension().and_then(OsStr::to_str) { + Some("h") | Some("hpp") => { + let func = entry.file_name().to_str().unwrap() + .replace(|c| !char::is_alphanumeric(c), "_") + .replace("__", "_") + .to_lowercase(); + writeln!(dst, "test_header!(header_{}, {:?});", + func, entry.path()).unwrap(); + } + _ => {} + } + } + + dst.flush().unwrap(); + } +} + +fn main() { + codegen::main(); + testgen::main(); +} diff --git a/src/clang.rs b/src/clang.rs index b4acf2046f..e4703c4941 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -1,1758 +1,1758 @@ -//! A higher level Clang API built on top of the generated bindings in the -//! `clang_sys` module. - -#![allow(non_upper_case_globals, dead_code)] - - -use cexpr; -use clang_sys::*; -use regex; -use std::{mem, ptr, slice}; -use std::ffi::{CStr, CString}; -use std::fmt; -use std::hash::Hash; -use std::hash::Hasher; -use std::os::raw::{c_char, c_int, c_uint, c_ulong}; - -/// A cursor into the Clang AST, pointing to an AST node. -/// -/// We call the AST node pointed to by the cursor the cursor's "referent". -#[derive(Copy, Clone)] -pub struct Cursor { - x: CXCursor, -} - -impl fmt::Debug for Cursor { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "Cursor({} kind: {}, loc: {}, usr: {:?})", - self.spelling(), - kind_to_str(self.kind()), - self.location(), - self.usr()) - } -} - -impl Cursor { - /// Get the Unified Symbol Resolution for this cursor's referent, if - /// available. - /// - /// The USR can be used to compare entities across translation units. - pub fn usr(&self) -> Option { - let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; - if s.is_empty() { None } else { Some(s) } - } - - /// Is this cursor's referent a declaration? - pub fn is_declaration(&self) -> bool { - unsafe { clang_isDeclaration(self.kind()) != 0 } - } - - /// Get the null cursor, which has no referent. - pub fn null() -> Self { - Cursor { - x: unsafe { clang_getNullCursor() }, - } - } - - /// Get this cursor's referent's spelling. - pub fn spelling(&self) -> String { - unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } - } - - /// Get this cursor's referent's display name. - /// - /// This is not necessarily a valid identifier. It includes extra - /// information, such as parameters for a function, etc. - pub fn display_name(&self) -> String { - unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } - } - - /// Get the mangled name of this cursor's referent. - pub fn mangling(&self) -> String { - if clang_Cursor_getMangling::is_loaded() { - unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } - } else { - self.spelling() - } - } - - /// Returns whether the cursor refers to a built-in definition. - pub fn is_builtin(&self) -> bool { - let (file, _, _, _) = self.location().location(); - file.name().is_none() - } - - /// Get the `Cursor` for this cursor's referent's lexical parent. - /// - /// The lexical parent is the parent of the definition. The semantic parent - /// is the parent of the declaration. Generally, the lexical parent doesn't - /// have any effect on semantics, while the semantic parent does. - /// - /// In the following snippet, the `Foo` class would be the semantic parent - /// of the out-of-line `method` definition, while the lexical parent is the - /// translation unit. - /// - /// ```c++ - /// class Foo { - /// void method(); - /// }; - /// - /// void Foo::method() { /* ... */ } - /// ``` - pub fn lexical_parent(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getCursorLexicalParent(self.x), - } - } - } - - /// Get the referent's semantic parent, if one is available. - /// - /// See documentation for `lexical_parent` for details on semantic vs - /// lexical parents. - pub fn fallible_semantic_parent(&self) -> Option { - let sp = unsafe { - Cursor { - x: clang_getCursorSemanticParent(self.x), - } - }; - if sp == *self || !sp.is_valid() { - return None; - } - Some(sp) - } - - /// Get the referent's semantic parent. - /// - /// See documentation for `lexical_parent` for details on semantic vs - /// lexical parents. - pub fn semantic_parent(&self) -> Cursor { - self.fallible_semantic_parent().unwrap() - } - - /// Return the number of template arguments used by this cursor's referent, - /// if the referent is either a template instantiation. Returns `None` - /// otherwise. - /// - /// NOTE: This may not return `Some` for partial template specializations, - /// see #193 and #194. - pub fn num_template_args(&self) -> Option { - // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while - // `clang_Cursor_getNumTemplateArguments` is totally unreliable. - // Therefore, try former first, and only fallback to the latter if we - // have to. - self.cur_type() - .num_template_args() - .or_else(|| { - let n: c_int = - unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; - - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None - } - }) - .or_else(|| { - let canonical = self.canonical(); - if canonical != *self { - canonical.num_template_args() - } else { - None - } - }) - } - - /// Get a cursor pointing to this referent's containing translation unit. - /// - /// Note that we shouldn't create a `TranslationUnit` struct here, because - /// bindgen assumes there will only be one of them alive at a time, and - /// disposes it on drop. That can change if this would be required, but I - /// think we can survive fine without it. - pub fn translation_unit(&self) -> Cursor { - assert!(self.is_valid()); - unsafe { - let tu = clang_Cursor_getTranslationUnit(self.x); - let cursor = Cursor { - x: clang_getTranslationUnitCursor(tu), - }; - assert!(cursor.is_valid()); - cursor - } - } - - /// Is the referent a top level construct? - pub fn is_toplevel(&self) -> bool { - let mut semantic_parent = self.fallible_semantic_parent(); - - while semantic_parent.is_some() && - (semantic_parent.unwrap().kind() == CXCursor_Namespace || - semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || - semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { - semantic_parent = semantic_parent.unwrap() - .fallible_semantic_parent(); - } - - let tu = self.translation_unit(); - // Yes, this can happen with, e.g., macro definitions. - semantic_parent == tu.fallible_semantic_parent() - } - - /// There are a few kinds of types that we need to treat specially, mainly - /// not tracking the type declaration but the location of the cursor, given - /// clang doesn't expose a proper declaration for these types. - pub fn is_template_like(&self) -> bool { - match self.kind() { - CXCursor_ClassTemplate | - CXCursor_ClassTemplatePartialSpecialization | - CXCursor_TypeAliasTemplateDecl => true, - _ => false, - } - } - - /// Get the kind of referent this cursor is pointing to. - pub fn kind(&self) -> CXCursorKind { - self.x.kind - } - - /// Returns true is the cursor is a definition - pub fn is_definition(&self) -> bool { - unsafe { clang_isCursorDefinition(self.x) != 0 } - } - - /// Is the referent a template specialization? - pub fn is_template_specialization(&self) -> bool { - self.specialized().is_some() - } - - /// Is the referent a fully specialized template specialization without any - /// remaining free template arguments? - pub fn is_fully_specialized_template(&self) -> bool { - self.is_template_specialization() && - self.kind() != CXCursor_ClassTemplatePartialSpecialization && - self.num_template_args().unwrap_or(0) > 0 - } - - /// Is the referent a template specialization that still has remaining free - /// template arguments? - pub fn is_in_non_fully_specialized_template(&self) -> bool { - if self.is_toplevel() { - return false; - } - - let parent = self.semantic_parent(); - if parent.is_fully_specialized_template() { - return false; - } - - if !parent.is_template_like() { - return parent.is_in_non_fully_specialized_template(); - } - - return true; - } - - /// Is this cursor pointing a valid referent? - pub fn is_valid(&self) -> bool { - unsafe { clang_isInvalid(self.kind()) == 0 } - } - - /// Get the source location for the referent. - pub fn location(&self) -> SourceLocation { - unsafe { - SourceLocation { - x: clang_getCursorLocation(self.x), - } - } - } - - /// Get the source location range for the referent. - pub fn extent(&self) -> CXSourceRange { - unsafe { clang_getCursorExtent(self.x) } - } - - /// Get the raw declaration comment for this referent, if one exists. - pub fn raw_comment(&self) -> Option { - let s = unsafe { - cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) - }; - if s.is_empty() { None } else { Some(s) } - } - - /// Get the referent's parsed comment. - pub fn comment(&self) -> Comment { - unsafe { - Comment { - x: clang_Cursor_getParsedComment(self.x), - } - } - } - - /// Get the referent's type. - pub fn cur_type(&self) -> Type { - unsafe { - Type { - x: clang_getCursorType(self.x), - } - } - } - - /// Given that this cursor's referent is a reference to another type, or is - /// a declaration, get the cursor pointing to the referenced type or type of - /// the declared thing. - pub fn definition(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getCursorDefinition(self.x), - }; - - if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound { - Some(ret) - } else { - None - } - } - } - - /// Given that this cursor's referent is reference type, get the cursor - /// pointing to the referenced type. - pub fn referenced(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getCursorReferenced(self.x), - }; - - if ret.is_valid() { Some(ret) } else { None } - } - } - - /// Get the canonical cursor for this referent. - /// - /// Many types can be declared multiple times before finally being properly - /// defined. This method allows us to get the canonical cursor for the - /// referent type. - pub fn canonical(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getCanonicalCursor(self.x), - } - } - } - - /// Given that this cursor points to either a template specialization or a - /// template instantiation, get a cursor pointing to the template definition - /// that is being specialized. - pub fn specialized(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getSpecializedCursorTemplate(self.x), - }; - if ret.is_valid() { Some(ret) } else { None } - } - } - - /// Assuming that this cursor's referent is a template declaration, get the - /// kind of cursor that would be generated for its specializations. - pub fn template_kind(&self) -> CXCursorKind { - unsafe { clang_getTemplateCursorKind(self.x) } - } - - /// Traverse this cursor's referent and its children. - /// - /// Call the given function on each AST node traversed. - pub fn visit(&self, mut visitor: Visitor) - where Visitor: FnMut(Cursor) -> CXChildVisitResult, - { - unsafe { - clang_visitChildren(self.x, - visit_children::, - mem::transmute(&mut visitor)); - } - } - - /// Collect all of this cursor's children into a vec and return them. - pub fn collect_children(&self) -> Vec { - let mut children = vec![]; - self.visit(|c| { - children.push(c); - CXChildVisit_Continue - }); - children - } - - /// Does this cursor have any children? - pub fn has_children(&self) -> bool { - let mut has_children = false; - self.visit(|_| { - has_children = true; - CXChildVisit_Break - }); - has_children - } - - /// Does this cursor have at least `n` children? - pub fn has_at_least_num_children(&self, n: usize) -> bool { - assert!(n > 0); - let mut num_left = n; - self.visit(|_| { - num_left -= 1; - if num_left == 0 { - CXChildVisit_Break - } else { - CXChildVisit_Continue - } - }); - num_left == 0 - } - - /// Returns whether the given location contains a cursor with the given - /// kind in the first level of nesting underneath (doesn't look - /// recursively). - pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { - let mut found = false; - - self.visit(|c| if c.kind() == kind { - found = true; - CXChildVisit_Break - } else { - CXChildVisit_Continue - }); - - found - } - - /// Is the referent an inlined function? - pub fn is_inlined_function(&self) -> bool { - clang_Cursor_isFunctionInlined::is_loaded() && - unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } - } - - /// Get the width of this cursor's referent bit field, or `None` if the - /// referent is not a bit field. - pub fn bit_width(&self) -> Option { - unsafe { - let w = clang_getFieldDeclBitWidth(self.x); - if w == -1 { None } else { Some(w as u32) } - } - } - - /// Get the integer representation type used to hold this cursor's referent - /// enum type. - pub fn enum_type(&self) -> Option { - unsafe { - let t = Type { - x: clang_getEnumDeclIntegerType(self.x), - }; - if t.is_valid() { Some(t) } else { None } - } - } - - /// Get the signed constant value for this cursor's enum variant referent. - /// - /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_signed(&self) -> Option { - unsafe { - if self.kind() == CXCursor_EnumConstantDecl { - Some(clang_getEnumConstantDeclValue(self.x) as i64) - } else { - None - } - } - } - - /// Get the unsigned constant value for this cursor's enum variant referent. - /// - /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_unsigned(&self) -> Option { - unsafe { - if self.kind() == CXCursor_EnumConstantDecl { - Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) - } else { - None - } - } - } - - /// Given that this cursor's referent is a `typedef`, get the `Type` that is - /// being aliased. - pub fn typedef_type(&self) -> Option { - let inner = Type { - x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, - }; - - if inner.is_valid() { Some(inner) } else { None } - } - - /// Get the linkage kind for this cursor's referent. - /// - /// This only applies to functions and variables. - pub fn linkage(&self) -> CXLinkageKind { - unsafe { clang_getCursorLinkage(self.x) } - } - - /// Get the visibility of this cursor's referent. - pub fn visibility(&self) -> CXVisibilityKind { - if clang_getCursorVisibility::is_loaded() { - unsafe { clang_getCursorVisibility(self.x) } - } else { - CXVisibility_Default - } - } - - /// Given that this cursor's referent is a function, return cursors to its - /// parameters. - pub fn args(&self) -> Option> { - // XXX: We might want to use and keep num_args - // match self.kind() { - // CXCursor_FunctionDecl | - // CXCursor_CXXMethod => { - unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { - None - } else { - let num = w as u32; - - let mut args = vec![]; - for i in 0..num { - args.push(Cursor { - x: clang_Cursor_getArgument(self.x, i as c_uint), - }); - } - Some(args) - } - } - } - - /// Given that this cursor's referent is a function/method call or - /// declaration, return the number of arguments it takes. - /// - /// Returns -1 if the cursor's referent is not a function/method call or - /// declaration. - pub fn num_args(&self) -> Result { - unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { Err(()) } else { Ok(w as u32) } - } - } - - /// Get the access specifier for this cursor's referent. - pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { - unsafe { clang_getCXXAccessSpecifier(self.x) } - } - - /// Is this cursor's referent a field declaration that is marked as - /// `mutable`? - pub fn is_mutable_field(&self) -> bool { - clang_CXXField_isMutable::is_loaded() && - unsafe { clang_CXXField_isMutable(self.x) != 0 } - } - - /// Get the offset of the field represented by the Cursor. - pub fn offset_of_field(&self) -> Result { - if !clang_Cursor_getOffsetOfField::is_loaded() { - return Err(LayoutError::from(-1)); - } - - let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; - - if offset < 0 { - Err(LayoutError::from(offset as i32)) - } else { - Ok(offset as usize) - } - } - - /// Is this cursor's referent a member function that is declared `static`? - pub fn method_is_static(&self) -> bool { - unsafe { clang_CXXMethod_isStatic(self.x) != 0 } - } - - /// Is this cursor's referent a member function that is declared `const`? - pub fn method_is_const(&self) -> bool { - unsafe { clang_CXXMethod_isConst(self.x) != 0 } - } - - /// Is this cursor's referent a member function that is declared `const`? - pub fn method_is_virtual(&self) -> bool { - unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } - } - - /// Is this cursor's referent a struct or class with virtual members? - pub fn is_virtual_base(&self) -> bool { - unsafe { clang_isVirtualBase(self.x) != 0 } - } - - /// Try to evaluate this cursor. - pub fn evaluate(&self) -> Option { - EvalResult::new(*self) - } - - /// Return the result type for this cursor - pub fn ret_type(&self) -> Option { - let rt = Type { - x: unsafe { clang_getCursorResultType(self.x) }, - }; - if rt.is_valid() { Some(rt) } else { None } - } -} - -/// Checks whether the name looks like an identifier, i.e. is alphanumeric -/// (including '_') and does not start with a digit. -pub fn is_valid_identifier(name: &str) -> bool { - let mut chars = name.chars(); - let first_valid = chars.next() - .map(|c| c.is_alphabetic() || c == '_') - .unwrap_or(false); - - first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') -} - -extern "C" fn visit_children(cur: CXCursor, - _parent: CXCursor, - data: CXClientData) - -> CXChildVisitResult - where Visitor: FnMut(Cursor) -> CXChildVisitResult, -{ - let func: &mut Visitor = unsafe { mem::transmute(data) }; - let child = Cursor { - x: cur, - }; - - (*func)(child) -} - -impl PartialEq for Cursor { - fn eq(&self, other: &Cursor) -> bool { - unsafe { clang_equalCursors(self.x, other.x) == 1 } - } -} - -impl Eq for Cursor {} - -impl Hash for Cursor { - fn hash(&self, state: &mut H) { - unsafe { clang_hashCursor(self.x) }.hash(state) - } -} - -/// The type of a node in clang's AST. -#[derive(Clone, Copy)] -pub struct Type { - x: CXType, -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - unsafe { clang_equalTypes(self.x, other.x) != 0 } - } -} - -impl Eq for Type {} - -impl fmt::Debug for Type { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})", - self.spelling(), - type_to_str(self.kind()), - self.call_conv(), - self.declaration(), - self.declaration().canonical()) - } -} - -/// An error about the layout of a struct, class, or type. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum LayoutError { - /// Asked for the layout of an invalid type. - Invalid, - /// Asked for the layout of an incomplete type. - Incomplete, - /// Asked for the layout of a dependent type. - Dependent, - /// Asked for the layout of a type that does not have constant size. - NotConstantSize, - /// Asked for the layout of a field in a type that does not have such a - /// field. - InvalidFieldName, - /// An unknown layout error. - Unknown, -} - -impl ::std::convert::From for LayoutError { - fn from(val: i32) -> Self { - use self::LayoutError::*; - - match val { - CXTypeLayoutError_Invalid => Invalid, - CXTypeLayoutError_Incomplete => Incomplete, - CXTypeLayoutError_Dependent => Dependent, - CXTypeLayoutError_NotConstantSize => NotConstantSize, - CXTypeLayoutError_InvalidFieldName => InvalidFieldName, - _ => Unknown, - } - } -} - -impl Type { - /// Get this type's kind. - pub fn kind(&self) -> CXTypeKind { - self.x.kind - } - - /// Get a cursor pointing to this type's declaration. - pub fn declaration(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTypeDeclaration(self.x), - } - } - } - - /// Get the canonical declaration of this type, if it is available. - pub fn canonical_declaration(&self, - location: Option<&Cursor>) - -> Option { - let mut declaration = self.declaration(); - if !declaration.is_valid() { - if let Some(location) = location { - let mut location = *location; - if let Some(referenced) = location.referenced() { - location = referenced; - } - if location.is_template_like() { - declaration = location; - } - } - } - - let canonical = declaration.canonical(); - if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound { - Some(CanonicalTypeDeclaration(*self, canonical)) - } else { - None - } - } - - /// Get a raw display name for this type. - pub fn spelling(&self) -> String { - let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; - // Clang 5.0 introduced changes in the spelling API so it returned the - // full qualified name. Let's undo that here. - if s.split("::").all(|s| is_valid_identifier(s)) { - if let Some(s) = s.split("::").last() { - return s.to_owned(); - } - } - - s - } - - /// Is this type const qualified? - pub fn is_const(&self) -> bool { - unsafe { clang_isConstQualifiedType(self.x) != 0 } - } - - /// What is the size of this type? Paper over invalid types by returning `0` - /// for them. - pub fn size(&self) -> usize { - unsafe { - let val = clang_Type_getSizeOf(self.x); - if val < 0 { 0 } else { val as usize } - } - } - - /// What is the size of this type? - pub fn fallible_size(&self) -> Result { - let val = unsafe { clang_Type_getSizeOf(self.x) }; - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) - } - } - - /// What is the alignment of this type? Paper over invalid types by - /// returning `0`. - pub fn align(&self) -> usize { - unsafe { - let val = clang_Type_getAlignOf(self.x); - if val < 0 { 0 } else { val as usize } - } - } - - /// What is the alignment of this type? - pub fn fallible_align(&self) -> Result { - unsafe { - let val = clang_Type_getAlignOf(self.x); - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) - } - } - } - - /// Get the layout for this type, or an error describing why it does not - /// have a valid layout. - pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { - use ir::layout::Layout; - let size = try!(self.fallible_size()); - let align = try!(self.fallible_align()); - Ok(Layout::new(size, align)) - } - - /// Get the number of template arguments this type has, or `None` if it is - /// not some kind of template. - pub fn num_template_args(&self) -> Option { - let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None - } - } - - /// If this type is a class template specialization, return its - /// template arguments. Otherwise, return None. - pub fn template_args(&self) -> Option { - self.num_template_args().map(|n| { - TypeTemplateArgIterator { - x: self.x, - length: n, - index: 0, - } - }) - } - - /// Given that this type is a pointer type, return the type that it points - /// to. - pub fn pointee_type(&self) -> Option { - match self.kind() { - CXType_Pointer | - CXType_RValueReference | - CXType_LValueReference | - CXType_MemberPointer | - CXType_ObjCObjectPointer => { - let ret = Type { - x: unsafe { clang_getPointeeType(self.x) }, - }; - debug_assert!(ret.is_valid()); - Some(ret) - } - _ => None, - } - } - - /// Given that this type is an array, vector, or complex type, return the - /// type of its elements. - pub fn elem_type(&self) -> Option { - let current_type = Type { - x: unsafe { clang_getElementType(self.x) }, - }; - if current_type.is_valid() { - Some(current_type) - } else { - None - } - } - - /// Given that this type is an array or vector type, return its number of - /// elements. - pub fn num_elements(&self) -> Option { - let num_elements_returned = unsafe { clang_getNumElements(self.x) }; - if num_elements_returned != -1 { - Some(num_elements_returned as usize) - } else { - None - } - } - - /// Get the canonical version of this type. This sees through `typdef`s and - /// aliases to get the underlying, canonical type. - pub fn canonical_type(&self) -> Type { - unsafe { - Type { - x: clang_getCanonicalType(self.x), - } - } - } - - /// Is this type a variadic function type? - pub fn is_variadic(&self) -> bool { - unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } - } - - /// Given that this type is a function type, get the type of its return - /// value. - pub fn ret_type(&self) -> Option { - let rt = Type { - x: unsafe { clang_getResultType(self.x) }, - }; - if rt.is_valid() { Some(rt) } else { None } - } - - /// Given that this type is a function type, get its calling convention. If - /// this is not a function type, `CXCallingConv_Invalid` is returned. - pub fn call_conv(&self) -> CXCallingConv { - unsafe { clang_getFunctionTypeCallingConv(self.x) } - } - - /// For elaborated types (types which use `class`, `struct`, or `union` to - /// disambiguate types from local bindings), get the underlying type. - pub fn named(&self) -> Type { - unsafe { - Type { - x: if clang_Type_getNamedType::is_loaded() { - clang_Type_getNamedType(self.x) - } else { - self.x - }, - } - } - } - - /// Is this a valid type? - pub fn is_valid(&self) -> bool { - self.kind() != CXType_Invalid - } - - /// Is this a valid and exposed type? - pub fn is_valid_and_exposed(&self) -> bool { - self.is_valid() && self.kind() != CXType_Unexposed - } - - /// Is this type a fully instantiated template? - pub fn is_fully_instantiated_template(&self) -> bool { - // Yep, the spelling of this containing type-parameter is extremely - // nasty... But can happen in . Unfortunately I couldn't - // reduce it enough :( - self.template_args().map_or(false, |args| args.len() > 0) && - match self.declaration().kind() { - CXCursor_ClassTemplatePartialSpecialization | - CXCursor_TypeAliasTemplateDecl | - CXCursor_TemplateTemplateParameter => false, - _ => true, - } - } - - /// Is this type an associated template type? Eg `T::Associated` in - /// this example: - /// - /// ```c++ - /// template - /// class Foo { - /// typename T::Associated member; - /// }; - /// ``` - pub fn is_associated_type(&self) -> bool { - // This is terrible :( - fn hacky_parse_associated_type>(spelling: S) -> bool { - lazy_static! { - static ref ASSOC_TYPE_RE: regex::Regex = - regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap(); - } - ASSOC_TYPE_RE.is_match(spelling.as_ref()) - } - - self.kind() == CXType_Unexposed && - (hacky_parse_associated_type(self.spelling()) || - hacky_parse_associated_type(self.canonical_type().spelling())) - } -} - -/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its -/// cursor is the canonical declaration for its type. If you have a -/// `CanonicalTypeDeclaration` instance, you know for sure that the type and -/// cursor match up in a canonical declaration relationship, and it simply -/// cannot be otherwise. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CanonicalTypeDeclaration(Type, Cursor); - -impl CanonicalTypeDeclaration { - /// Get the type. - pub fn ty(&self) -> &Type { - &self.0 - } - - /// Get the type's canonical declaration cursor. - pub fn cursor(&self) -> &Cursor { - &self.1 - } -} - -/// An iterator for a type's template arguments. -pub struct TypeTemplateArgIterator { - x: CXType, - length: u32, - index: u32, -} - -impl Iterator for TypeTemplateArgIterator { - type Item = Type; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index as c_uint; - self.index += 1; - Some(Type { - x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, - }) - } else { - None - } - } -} - -impl ExactSizeIterator for TypeTemplateArgIterator { - fn len(&self) -> usize { - assert!(self.index <= self.length); - (self.length - self.index) as usize - } -} - -/// A `SourceLocation` is a file, line, column, and byte offset location for -/// some source text. -pub struct SourceLocation { - x: CXSourceLocation, -} - -impl SourceLocation { - /// Get the (file, line, column, byte offset) tuple for this source - /// location. - pub fn location(&self) -> (File, usize, usize, usize) { - unsafe { - let mut file = mem::zeroed(); - let mut line = 0; - let mut col = 0; - let mut off = 0; - clang_getSpellingLocation(self.x, - &mut file, - &mut line, - &mut col, - &mut off); - (File { - x: file, - }, - line as usize, - col as usize, - off as usize) - } - } -} - -impl fmt::Display for SourceLocation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (file, line, col, _) = self.location(); - if let Some(name) = file.name() { - write!(f, "{}:{}:{}", name, line, col) - } else { - "builtin definitions".fmt(f) - } - } -} - -/// A comment in the source text. -/// -/// Comments are sort of parsed by Clang, and have a tree structure. -pub struct Comment { - x: CXComment, -} - -impl Comment { - /// What kind of comment is this? - pub fn kind(&self) -> CXCommentKind { - unsafe { clang_Comment_getKind(self.x) } - } - - /// Get this comment's children comment - pub fn get_children(&self) -> CommentChildrenIterator { - CommentChildrenIterator { - parent: self.x, - length: unsafe { clang_Comment_getNumChildren(self.x) }, - index: 0, - } - } - - /// Given that this comment is the start or end of an HTML tag, get its tag - /// name. - pub fn get_tag_name(&self) -> String { - unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } - } - - /// Given that this comment is an HTML start tag, get its attributes. - pub fn get_tag_attrs(&self) -> CommentAttributesIterator { - CommentAttributesIterator { - x: self.x, - length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, - index: 0, - } - } -} - -/// An iterator for a comment's children -pub struct CommentChildrenIterator { - parent: CXComment, - length: c_uint, - index: c_uint, -} - -impl Iterator for CommentChildrenIterator { - type Item = Comment; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(Comment { - x: unsafe { clang_Comment_getChild(self.parent, idx) }, - }) - } else { - None - } - } -} - -/// An HTML start tag comment attribute -pub struct CommentAttribute { - /// HTML start tag attribute name - pub name: String, - /// HTML start tag attribute value - pub value: String, -} - -/// An iterator for a comment's attributes -pub struct CommentAttributesIterator { - x: CXComment, - length: c_uint, - index: c_uint, -} - -impl Iterator for CommentAttributesIterator { - type Item = CommentAttribute; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(CommentAttribute { - name: unsafe { - cxstring_into_string( - clang_HTMLStartTag_getAttrName(self.x, idx)) - }, - value: unsafe { - cxstring_into_string( - clang_HTMLStartTag_getAttrValue(self.x, idx)) - }, - }) - } else { - None - } - } -} - -/// A source file. -pub struct File { - x: CXFile, -} - -impl File { - /// Get the name of this source file. - pub fn name(&self) -> Option { - if self.x.is_null() { - return None; - } - Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) - } -} - -fn cxstring_into_string(s: CXString) -> String { - if s.data.is_null() { - return "".to_owned(); - } - unsafe { - let c_str = CStr::from_ptr(clang_getCString(s) as *const _); - let ret = c_str.to_string_lossy().into_owned(); - clang_disposeString(s); - ret - } -} - -/// An `Index` is an environment for a set of translation units that will -/// typically end up linked together in one final binary. -pub struct Index { - x: CXIndex, -} - -impl Index { - /// Construct a new `Index`. - /// - /// The `pch` parameter controls whether declarations in pre-compiled - /// headers are included when enumerating a translation unit's "locals". - /// - /// The `diag` parameter controls whether debugging diagnostics are enabled. - pub fn new(pch: bool, diag: bool) -> Index { - unsafe { - Index { - x: clang_createIndex(pch as c_int, diag as c_int), - } - } - } -} - -impl fmt::Debug for Index { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Index {{ }}") - } -} - -impl Drop for Index { - fn drop(&mut self) { - unsafe { - clang_disposeIndex(self.x); - } - } -} - -/// A token emitted by clang's lexer. -#[derive(Debug)] -pub struct Token { - /// The kind of token this is. - pub kind: CXTokenKind, - /// A display name for this token. - pub spelling: String, -} - -/// A translation unit (or "compilation unit"). -pub struct TranslationUnit { - x: CXTranslationUnit, -} - -impl fmt::Debug for TranslationUnit { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "TranslationUnit {{ }}") - } -} - -impl TranslationUnit { - /// Parse a source file into a translation unit. - pub fn parse(ix: &Index, - file: &str, - cmd_args: &[String], - unsaved: &[UnsavedFile], - opts: CXTranslationUnit_Flags) - -> Option { - let fname = CString::new(file).unwrap(); - let _c_args: Vec = - cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect(); - let c_args: Vec<*const c_char> = - _c_args.iter().map(|s| s.as_ptr()).collect(); - let mut c_unsaved: Vec = - unsaved.iter().map(|f| f.x).collect(); - let tu = unsafe { - clang_parseTranslationUnit(ix.x, - fname.as_ptr(), - c_args.as_ptr(), - c_args.len() as c_int, - c_unsaved.as_mut_ptr(), - c_unsaved.len() as c_uint, - opts) - }; - if tu.is_null() { - None - } else { - Some(TranslationUnit { - x: tu, - }) - } - } - - /// Get the Clang diagnostic information associated with this translation - /// unit. - pub fn diags(&self) -> Vec { - unsafe { - let num = clang_getNumDiagnostics(self.x) as usize; - let mut diags = vec![]; - for i in 0..num { - diags.push(Diagnostic { - x: clang_getDiagnostic(self.x, i as c_uint), - }); - } - diags - } - } - - /// Get a cursor pointing to the root of this translation unit's AST. - pub fn cursor(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTranslationUnitCursor(self.x), - } - } - } - - /// Is this the null translation unit? - pub fn is_null(&self) -> bool { - self.x.is_null() - } - - /// Invoke Clang's lexer on this translation unit and get the stream of - /// tokens that come out. - pub fn tokens(&self, cursor: &Cursor) -> Option> { - let range = cursor.extent(); - let mut tokens = vec![]; - unsafe { - let mut token_ptr = ptr::null_mut(); - let mut num_tokens: c_uint = 0; - clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens); - if token_ptr.is_null() { - return None; - } - - let token_array = slice::from_raw_parts(token_ptr, - num_tokens as usize); - for &token in token_array.iter() { - let kind = clang_getTokenKind(token); - let spelling = - cxstring_into_string(clang_getTokenSpelling(self.x, token)); - - tokens.push(Token { - kind: kind, - spelling: spelling, - }); - } - clang_disposeTokens(self.x, token_ptr, num_tokens); - } - Some(tokens) - } - - /// Convert a set of tokens from clang into `cexpr` tokens, for further - /// processing. - pub fn cexpr_tokens(&self, - cursor: &Cursor) - -> Option> { - use cexpr::token; - - let mut tokens = match self.tokens(cursor) { - Some(tokens) => tokens, - None => return None, - }; - - // FIXME(emilio): LLVM 3.9 at least always include an extra token for no - // good reason (except if we're at EOF). So we do this kind of hack, - // where we skip known-to-cause problems trailing punctuation and - // trailing keywords. - // - // This is sort of unfortunate, though :(. - // - // I'll try to get it fixed in LLVM if I have the time to submit a - // patch. - let mut trim_last_token = false; - if let Some(token) = tokens.last() { - // The starting of the next macro. - trim_last_token |= token.spelling == "#" && - token.kind == CXToken_Punctuation; - - // A following keyword of any kind, like a following declaration. - trim_last_token |= token.kind == CXToken_Keyword; - } - - if trim_last_token { - tokens.pop().unwrap(); - } - - Some(tokens.into_iter() - .filter_map(|token| { - let kind = match token.kind { - CXToken_Punctuation => token::Kind::Punctuation, - CXToken_Literal => token::Kind::Literal, - CXToken_Identifier => token::Kind::Identifier, - CXToken_Keyword => token::Kind::Keyword, - // NB: cexpr is not too happy about comments inside - // expressions, so we strip them down here. - CXToken_Comment => return None, - _ => { - panic!("Found unexpected token kind: {:?}", token.kind) - } - }; - - Some(token::Token { - kind: kind, - raw: token.spelling.into_bytes().into_boxed_slice(), - }) - }) - .collect::>()) - } -} - -impl Drop for TranslationUnit { - fn drop(&mut self) { - unsafe { - clang_disposeTranslationUnit(self.x); - } - } -} - - -/// A diagnostic message generated while parsing a translation unit. -pub struct Diagnostic { - x: CXDiagnostic, -} - -impl Diagnostic { - /// Format this diagnostic message as a string, using the given option bit - /// flags. - pub fn format(&self) -> String { - unsafe { - let opts = clang_defaultDiagnosticDisplayOptions(); - cxstring_into_string(clang_formatDiagnostic(self.x, opts)) - } - } - - /// What is the severity of this diagnostic message? - pub fn severity(&self) -> CXDiagnosticSeverity { - unsafe { clang_getDiagnosticSeverity(self.x) } - } -} - -impl Drop for Diagnostic { - /// Destroy this diagnostic message. - fn drop(&mut self) { - unsafe { - clang_disposeDiagnostic(self.x); - } - } -} - -/// A file which has not been saved to disk. -pub struct UnsavedFile { - x: CXUnsavedFile, - /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in - /// `CXUnsavedFile`. - pub name: CString, - contents: CString, -} - -impl UnsavedFile { - /// Construct a new unsaved file with the given `name` and `contents`. - pub fn new(name: &str, contents: &str) -> UnsavedFile { - let name = CString::new(name).unwrap(); - let contents = CString::new(contents).unwrap(); - let x = CXUnsavedFile { - Filename: name.as_ptr(), - Contents: contents.as_ptr(), - Length: contents.as_bytes().len() as c_ulong, - }; - UnsavedFile { - x: x, - name: name, - contents: contents, - } - } -} - -impl fmt::Debug for UnsavedFile { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "UnsavedFile(name: {:?}, contents: {:?})", - self.name, - self.contents) - } -} - -/// Convert a cursor kind into a static string. -pub fn kind_to_str(x: CXCursorKind) -> String { - unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } -} - -/// Convert a type kind to a static string. -pub fn type_to_str(x: CXTypeKind) -> String { - unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } -} - -/// Dump the Clang AST to stdout for debugging purposes. -pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { - fn print_indent>(depth: isize, s: S) { - for _ in 0..depth { - print!(" "); - } - println!("{}", s.as_ref()); - } - - fn print_cursor>(depth: isize, prefix: S, c: &Cursor) { - let prefix = prefix.as_ref(); - print_indent(depth, - format!(" {}kind = {}", prefix, kind_to_str(c.kind()))); - print_indent(depth, - format!(" {}spelling = \"{}\"", prefix, c.spelling())); - print_indent(depth, format!(" {}location = {}", prefix, c.location())); - print_indent(depth, - format!(" {}is-definition? {}", - prefix, - c.is_definition())); - print_indent(depth, - format!(" {}is-declaration? {}", - prefix, - c.is_declaration())); - print_indent(depth, - format!(" {}is-inlined-function? {}", - prefix, - c.is_inlined_function())); - - let templ_kind = c.template_kind(); - if templ_kind != CXCursor_NoDeclFound { - print_indent(depth, - format!(" {}template-kind = {}", - prefix, - kind_to_str(templ_kind))); - } - if let Some(usr) = c.usr() { - print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); - } - if let Ok(num) = c.num_args() { - print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); - } - if let Some(num) = c.num_template_args() { - print_indent(depth, - format!(" {}number-of-template-args = {}", - prefix, - num)); - } - if let Some(width) = c.bit_width() { - print_indent(depth, format!(" {}bit-width = {}", prefix, width)); - } - if let Some(ty) = c.enum_type() { - print_indent(depth, - format!(" {}enum-type = {}", - prefix, - type_to_str(ty.kind()))); - } - if let Some(val) = c.enum_val_signed() { - print_indent(depth, format!(" {}enum-val = {}", prefix, val)); - } - if let Some(ty) = c.typedef_type() { - print_indent(depth, - format!(" {}typedef-type = {}", - prefix, - type_to_str(ty.kind()))); - } - if let Some(ty) = c.ret_type() { - print_indent(depth, - format!(" {}ret-type = {}", - prefix, - type_to_str(ty.kind()))); - } - - if let Some(refd) = c.referenced() { - if refd != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "referenced.", - &refd); - } - } - - let canonical = c.canonical(); - if canonical != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "canonical.", - &canonical); - } - - if let Some(specialized) = c.specialized() { - if specialized != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "specialized.", - &specialized); - } - } - - if let Some(parent) = c.fallible_semantic_parent() { - println!(""); - print_cursor(depth, - String::from(prefix) + "semantic-parent.", - &parent); - } - } - - fn print_type>(depth: isize, prefix: S, ty: &Type) { - let prefix = prefix.as_ref(); - - let kind = ty.kind(); - print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); - if kind == CXType_Invalid { - return; - } - - print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); - - print_indent(depth, - format!(" {}spelling = \"{}\"", prefix, ty.spelling())); - let num_template_args = - unsafe { clang_Type_getNumTemplateArguments(ty.x) }; - if num_template_args >= 0 { - print_indent(depth, - format!(" {}number-of-template-args = {}", - prefix, - num_template_args)); - } - if let Some(num) = ty.num_elements() { - print_indent(depth, - format!(" {}number-of-elements = {}", prefix, num)); - } - print_indent(depth, - format!(" {}is-variadic? {}", prefix, ty.is_variadic())); - - let canonical = ty.canonical_type(); - if canonical != *ty { - println!(""); - print_type(depth, String::from(prefix) + "canonical.", &canonical); - } - - if let Some(pointee) = ty.pointee_type() { - if pointee != *ty { - println!(""); - print_type(depth, String::from(prefix) + "pointee.", &pointee); - } - } - - if let Some(elem) = ty.elem_type() { - if elem != *ty { - println!(""); - print_type(depth, String::from(prefix) + "elements.", &elem); - } - } - - if let Some(ret) = ty.ret_type() { - if ret != *ty { - println!(""); - print_type(depth, String::from(prefix) + "return.", &ret); - } - } - - let named = ty.named(); - if named != *ty && named.is_valid() { - println!(""); - print_type(depth, String::from(prefix) + "named.", &named); - } - } - - print_indent(depth, "("); - print_cursor(depth, "", c); - - println!(""); - let ty = c.cur_type(); - print_type(depth, "type.", &ty); - - let declaration = ty.declaration(); - if declaration != *c && declaration.kind() != CXCursor_NoDeclFound { - println!(""); - print_cursor(depth, "type.declaration.", &declaration); - } - - // Recurse. - let mut found_children = false; - c.visit(|s| { - if !found_children { - println!(""); - found_children = true; - } - ast_dump(&s, depth + 1) - }); - - print_indent(depth, ")"); - - CXChildVisit_Continue -} - -/// Try to extract the clang version to a string -pub fn extract_clang_version() -> String { - unsafe { cxstring_into_string(clang_getClangVersion()) } -} - -/// A wrapper for the result of evaluating an expression. -#[derive(Debug)] -pub struct EvalResult { - x: CXEvalResult, -} - -impl EvalResult { - /// Evaluate `cursor` and return the result. - pub fn new(cursor: Cursor) -> Option { - if !clang_Cursor_Evaluate::is_loaded() { - return None; - } - - // Clang has an internal assertion we can trigger if we try to evaluate - // a cursor containing a variadic template type reference. Triggering - // the assertion aborts the process, and we don't want that. Clang - // *also* doesn't expose any API for finding variadic vs non-variadic - // template type references, let alone whether a type referenced is a - // template type, instead they seem to show up as type references to an - // unexposed type. Our solution is to just flat out ban all - // `CXType_Unexposed` from evaluation. - let mut found_cant_eval = false; - cursor.visit(|c| if c.kind() == CXCursor_TypeRef && - c.cur_type().kind() == CXType_Unexposed { - found_cant_eval = true; - CXChildVisit_Break - } else { - CXChildVisit_Recurse - }); - if found_cant_eval { - return None; - } - - Some(EvalResult { - x: unsafe { clang_Cursor_Evaluate(cursor.x) }, - }) - } - - fn kind(&self) -> CXEvalResultKind { - unsafe { clang_EvalResult_getKind(self.x) } - } - - /// Try to get back the result as a double. - pub fn as_double(&self) -> Option { - match self.kind() { - CXEval_Float => { - Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) - } - _ => None, - } - } - - /// Try to get back the result as an integer. - pub fn as_int(&self) -> Option { - match self.kind() { - CXEval_Int => { - Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32) - } - _ => None, - } - } - - /// Evaluates the expression as a literal string, that may or may not be - /// valid utf-8. - pub fn as_literal_string(&self) -> Option> { - match self.kind() { - CXEval_StrLiteral => { - let ret = unsafe { - CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) - }; - Some(ret.to_bytes().to_vec()) - } - _ => None, - } - } -} - -impl Drop for EvalResult { - fn drop(&mut self) { - unsafe { clang_EvalResult_dispose(self.x) }; - } -} +//! A higher level Clang API built on top of the generated bindings in the +//! `clang_sys` module. + +#![allow(non_upper_case_globals, dead_code)] + + +use cexpr; +use clang_sys::*; +use regex; +use std::{mem, ptr, slice}; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::hash::Hash; +use std::hash::Hasher; +use std::os::raw::{c_char, c_int, c_uint, c_ulong}; + +/// A cursor into the Clang AST, pointing to an AST node. +/// +/// We call the AST node pointed to by the cursor the cursor's "referent". +#[derive(Copy, Clone)] +pub struct Cursor { + x: CXCursor, +} + +impl fmt::Debug for Cursor { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Cursor({} kind: {}, loc: {}, usr: {:?})", + self.spelling(), + kind_to_str(self.kind()), + self.location(), + self.usr()) + } +} + +impl Cursor { + /// Get the Unified Symbol Resolution for this cursor's referent, if + /// available. + /// + /// The USR can be used to compare entities across translation units. + pub fn usr(&self) -> Option { + let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; + if s.is_empty() { None } else { Some(s) } + } + + /// Is this cursor's referent a declaration? + pub fn is_declaration(&self) -> bool { + unsafe { clang_isDeclaration(self.kind()) != 0 } + } + + /// Get the null cursor, which has no referent. + pub fn null() -> Self { + Cursor { + x: unsafe { clang_getNullCursor() }, + } + } + + /// Get this cursor's referent's spelling. + pub fn spelling(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } + } + + /// Get this cursor's referent's display name. + /// + /// This is not necessarily a valid identifier. It includes extra + /// information, such as parameters for a function, etc. + pub fn display_name(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } + } + + /// Get the mangled name of this cursor's referent. + pub fn mangling(&self) -> String { + if clang_Cursor_getMangling::is_loaded() { + unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } + } else { + self.spelling() + } + } + + /// Returns whether the cursor refers to a built-in definition. + pub fn is_builtin(&self) -> bool { + let (file, _, _, _) = self.location().location(); + file.name().is_none() + } + + /// Get the `Cursor` for this cursor's referent's lexical parent. + /// + /// The lexical parent is the parent of the definition. The semantic parent + /// is the parent of the declaration. Generally, the lexical parent doesn't + /// have any effect on semantics, while the semantic parent does. + /// + /// In the following snippet, the `Foo` class would be the semantic parent + /// of the out-of-line `method` definition, while the lexical parent is the + /// translation unit. + /// + /// ```c++ + /// class Foo { + /// void method(); + /// }; + /// + /// void Foo::method() { /* ... */ } + /// ``` + pub fn lexical_parent(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCursorLexicalParent(self.x), + } + } + } + + /// Get the referent's semantic parent, if one is available. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn fallible_semantic_parent(&self) -> Option { + let sp = unsafe { + Cursor { + x: clang_getCursorSemanticParent(self.x), + } + }; + if sp == *self || !sp.is_valid() { + return None; + } + Some(sp) + } + + /// Get the referent's semantic parent. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn semantic_parent(&self) -> Cursor { + self.fallible_semantic_parent().unwrap() + } + + /// Return the number of template arguments used by this cursor's referent, + /// if the referent is either a template instantiation. Returns `None` + /// otherwise. + /// + /// NOTE: This may not return `Some` for partial template specializations, + /// see #193 and #194. + pub fn num_template_args(&self) -> Option { + // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while + // `clang_Cursor_getNumTemplateArguments` is totally unreliable. + // Therefore, try former first, and only fallback to the latter if we + // have to. + self.cur_type() + .num_template_args() + .or_else(|| { + let n: c_int = + unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; + + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None + } + }) + .or_else(|| { + let canonical = self.canonical(); + if canonical != *self { + canonical.num_template_args() + } else { + None + } + }) + } + + /// Get a cursor pointing to this referent's containing translation unit. + /// + /// Note that we shouldn't create a `TranslationUnit` struct here, because + /// bindgen assumes there will only be one of them alive at a time, and + /// disposes it on drop. That can change if this would be required, but I + /// think we can survive fine without it. + pub fn translation_unit(&self) -> Cursor { + assert!(self.is_valid()); + unsafe { + let tu = clang_Cursor_getTranslationUnit(self.x); + let cursor = Cursor { + x: clang_getTranslationUnitCursor(tu), + }; + assert!(cursor.is_valid()); + cursor + } + } + + /// Is the referent a top level construct? + pub fn is_toplevel(&self) -> bool { + let mut semantic_parent = self.fallible_semantic_parent(); + + while semantic_parent.is_some() && + (semantic_parent.unwrap().kind() == CXCursor_Namespace || + semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || + semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { + semantic_parent = semantic_parent.unwrap() + .fallible_semantic_parent(); + } + + let tu = self.translation_unit(); + // Yes, this can happen with, e.g., macro definitions. + semantic_parent == tu.fallible_semantic_parent() + } + + /// There are a few kinds of types that we need to treat specially, mainly + /// not tracking the type declaration but the location of the cursor, given + /// clang doesn't expose a proper declaration for these types. + pub fn is_template_like(&self) -> bool { + match self.kind() { + CXCursor_ClassTemplate | + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_TypeAliasTemplateDecl => true, + _ => false, + } + } + + /// Get the kind of referent this cursor is pointing to. + pub fn kind(&self) -> CXCursorKind { + self.x.kind + } + + /// Returns true is the cursor is a definition + pub fn is_definition(&self) -> bool { + unsafe { clang_isCursorDefinition(self.x) != 0 } + } + + /// Is the referent a template specialization? + pub fn is_template_specialization(&self) -> bool { + self.specialized().is_some() + } + + /// Is the referent a fully specialized template specialization without any + /// remaining free template arguments? + pub fn is_fully_specialized_template(&self) -> bool { + self.is_template_specialization() && + self.kind() != CXCursor_ClassTemplatePartialSpecialization && + self.num_template_args().unwrap_or(0) > 0 + } + + /// Is the referent a template specialization that still has remaining free + /// template arguments? + pub fn is_in_non_fully_specialized_template(&self) -> bool { + if self.is_toplevel() { + return false; + } + + let parent = self.semantic_parent(); + if parent.is_fully_specialized_template() { + return false; + } + + if !parent.is_template_like() { + return parent.is_in_non_fully_specialized_template(); + } + + return true; + } + + /// Is this cursor pointing a valid referent? + pub fn is_valid(&self) -> bool { + unsafe { clang_isInvalid(self.kind()) == 0 } + } + + /// Get the source location for the referent. + pub fn location(&self) -> SourceLocation { + unsafe { + SourceLocation { + x: clang_getCursorLocation(self.x), + } + } + } + + /// Get the source location range for the referent. + pub fn extent(&self) -> CXSourceRange { + unsafe { clang_getCursorExtent(self.x) } + } + + /// Get the raw declaration comment for this referent, if one exists. + pub fn raw_comment(&self) -> Option { + let s = unsafe { + cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) + }; + if s.is_empty() { None } else { Some(s) } + } + + /// Get the referent's parsed comment. + pub fn comment(&self) -> Comment { + unsafe { + Comment { + x: clang_Cursor_getParsedComment(self.x), + } + } + } + + /// Get the referent's type. + pub fn cur_type(&self) -> Type { + unsafe { + Type { + x: clang_getCursorType(self.x), + } + } + } + + /// Given that this cursor's referent is a reference to another type, or is + /// a declaration, get the cursor pointing to the referenced type or type of + /// the declared thing. + pub fn definition(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getCursorDefinition(self.x), + }; + + if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound { + Some(ret) + } else { + None + } + } + } + + /// Given that this cursor's referent is reference type, get the cursor + /// pointing to the referenced type. + pub fn referenced(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getCursorReferenced(self.x), + }; + + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Get the canonical cursor for this referent. + /// + /// Many types can be declared multiple times before finally being properly + /// defined. This method allows us to get the canonical cursor for the + /// referent type. + pub fn canonical(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCanonicalCursor(self.x), + } + } + } + + /// Given that this cursor points to either a template specialization or a + /// template instantiation, get a cursor pointing to the template definition + /// that is being specialized. + pub fn specialized(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getSpecializedCursorTemplate(self.x), + }; + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Assuming that this cursor's referent is a template declaration, get the + /// kind of cursor that would be generated for its specializations. + pub fn template_kind(&self) -> CXCursorKind { + unsafe { clang_getTemplateCursorKind(self.x) } + } + + /// Traverse this cursor's referent and its children. + /// + /// Call the given function on each AST node traversed. + pub fn visit(&self, mut visitor: Visitor) + where Visitor: FnMut(Cursor) -> CXChildVisitResult, + { + unsafe { + clang_visitChildren(self.x, + visit_children::, + mem::transmute(&mut visitor)); + } + } + + /// Collect all of this cursor's children into a vec and return them. + pub fn collect_children(&self) -> Vec { + let mut children = vec![]; + self.visit(|c| { + children.push(c); + CXChildVisit_Continue + }); + children + } + + /// Does this cursor have any children? + pub fn has_children(&self) -> bool { + let mut has_children = false; + self.visit(|_| { + has_children = true; + CXChildVisit_Break + }); + has_children + } + + /// Does this cursor have at least `n` children? + pub fn has_at_least_num_children(&self, n: usize) -> bool { + assert!(n > 0); + let mut num_left = n; + self.visit(|_| { + num_left -= 1; + if num_left == 0 { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + num_left == 0 + } + + /// Returns whether the given location contains a cursor with the given + /// kind in the first level of nesting underneath (doesn't look + /// recursively). + pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { + let mut found = false; + + self.visit(|c| if c.kind() == kind { + found = true; + CXChildVisit_Break + } else { + CXChildVisit_Continue + }); + + found + } + + /// Is the referent an inlined function? + pub fn is_inlined_function(&self) -> bool { + clang_Cursor_isFunctionInlined::is_loaded() && + unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } + } + + /// Get the width of this cursor's referent bit field, or `None` if the + /// referent is not a bit field. + pub fn bit_width(&self) -> Option { + unsafe { + let w = clang_getFieldDeclBitWidth(self.x); + if w == -1 { None } else { Some(w as u32) } + } + } + + /// Get the integer representation type used to hold this cursor's referent + /// enum type. + pub fn enum_type(&self) -> Option { + unsafe { + let t = Type { + x: clang_getEnumDeclIntegerType(self.x), + }; + if t.is_valid() { Some(t) } else { None } + } + } + + /// Get the signed constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_signed(&self) -> Option { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclValue(self.x) as i64) + } else { + None + } + } + } + + /// Get the unsigned constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_unsigned(&self) -> Option { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) + } else { + None + } + } + } + + /// Given that this cursor's referent is a `typedef`, get the `Type` that is + /// being aliased. + pub fn typedef_type(&self) -> Option { + let inner = Type { + x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, + }; + + if inner.is_valid() { Some(inner) } else { None } + } + + /// Get the linkage kind for this cursor's referent. + /// + /// This only applies to functions and variables. + pub fn linkage(&self) -> CXLinkageKind { + unsafe { clang_getCursorLinkage(self.x) } + } + + /// Get the visibility of this cursor's referent. + pub fn visibility(&self) -> CXVisibilityKind { + if clang_getCursorVisibility::is_loaded() { + unsafe { clang_getCursorVisibility(self.x) } + } else { + CXVisibility_Default + } + } + + /// Given that this cursor's referent is a function, return cursors to its + /// parameters. + pub fn args(&self) -> Option> { + // XXX: We might want to use and keep num_args + // match self.kind() { + // CXCursor_FunctionDecl | + // CXCursor_CXXMethod => { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { + None + } else { + let num = w as u32; + + let mut args = vec![]; + for i in 0..num { + args.push(Cursor { + x: clang_Cursor_getArgument(self.x, i as c_uint), + }); + } + Some(args) + } + } + } + + /// Given that this cursor's referent is a function/method call or + /// declaration, return the number of arguments it takes. + /// + /// Returns -1 if the cursor's referent is not a function/method call or + /// declaration. + pub fn num_args(&self) -> Result { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { Err(()) } else { Ok(w as u32) } + } + } + + /// Get the access specifier for this cursor's referent. + pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { + unsafe { clang_getCXXAccessSpecifier(self.x) } + } + + /// Is this cursor's referent a field declaration that is marked as + /// `mutable`? + pub fn is_mutable_field(&self) -> bool { + clang_CXXField_isMutable::is_loaded() && + unsafe { clang_CXXField_isMutable(self.x) != 0 } + } + + /// Get the offset of the field represented by the Cursor. + pub fn offset_of_field(&self) -> Result { + if !clang_Cursor_getOffsetOfField::is_loaded() { + return Err(LayoutError::from(-1)); + } + + let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; + + if offset < 0 { + Err(LayoutError::from(offset as i32)) + } else { + Ok(offset as usize) + } + } + + /// Is this cursor's referent a member function that is declared `static`? + pub fn method_is_static(&self) -> bool { + unsafe { clang_CXXMethod_isStatic(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_const(&self) -> bool { + unsafe { clang_CXXMethod_isConst(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_virtual(&self) -> bool { + unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } + } + + /// Is this cursor's referent a struct or class with virtual members? + pub fn is_virtual_base(&self) -> bool { + unsafe { clang_isVirtualBase(self.x) != 0 } + } + + /// Try to evaluate this cursor. + pub fn evaluate(&self) -> Option { + EvalResult::new(*self) + } + + /// Return the result type for this cursor + pub fn ret_type(&self) -> Option { + let rt = Type { + x: unsafe { clang_getCursorResultType(self.x) }, + }; + if rt.is_valid() { Some(rt) } else { None } + } +} + +/// Checks whether the name looks like an identifier, i.e. is alphanumeric +/// (including '_') and does not start with a digit. +pub fn is_valid_identifier(name: &str) -> bool { + let mut chars = name.chars(); + let first_valid = chars.next() + .map(|c| c.is_alphabetic() || c == '_') + .unwrap_or(false); + + first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') +} + +extern "C" fn visit_children(cur: CXCursor, + _parent: CXCursor, + data: CXClientData) + -> CXChildVisitResult + where Visitor: FnMut(Cursor) -> CXChildVisitResult, +{ + let func: &mut Visitor = unsafe { mem::transmute(data) }; + let child = Cursor { + x: cur, + }; + + (*func)(child) +} + +impl PartialEq for Cursor { + fn eq(&self, other: &Cursor) -> bool { + unsafe { clang_equalCursors(self.x, other.x) == 1 } + } +} + +impl Eq for Cursor {} + +impl Hash for Cursor { + fn hash(&self, state: &mut H) { + unsafe { clang_hashCursor(self.x) }.hash(state) + } +} + +/// The type of a node in clang's AST. +#[derive(Clone, Copy)] +pub struct Type { + x: CXType, +} + +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + unsafe { clang_equalTypes(self.x, other.x) != 0 } + } +} + +impl Eq for Type {} + +impl fmt::Debug for Type { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})", + self.spelling(), + type_to_str(self.kind()), + self.call_conv(), + self.declaration(), + self.declaration().canonical()) + } +} + +/// An error about the layout of a struct, class, or type. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum LayoutError { + /// Asked for the layout of an invalid type. + Invalid, + /// Asked for the layout of an incomplete type. + Incomplete, + /// Asked for the layout of a dependent type. + Dependent, + /// Asked for the layout of a type that does not have constant size. + NotConstantSize, + /// Asked for the layout of a field in a type that does not have such a + /// field. + InvalidFieldName, + /// An unknown layout error. + Unknown, +} + +impl ::std::convert::From for LayoutError { + fn from(val: i32) -> Self { + use self::LayoutError::*; + + match val { + CXTypeLayoutError_Invalid => Invalid, + CXTypeLayoutError_Incomplete => Incomplete, + CXTypeLayoutError_Dependent => Dependent, + CXTypeLayoutError_NotConstantSize => NotConstantSize, + CXTypeLayoutError_InvalidFieldName => InvalidFieldName, + _ => Unknown, + } + } +} + +impl Type { + /// Get this type's kind. + pub fn kind(&self) -> CXTypeKind { + self.x.kind + } + + /// Get a cursor pointing to this type's declaration. + pub fn declaration(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTypeDeclaration(self.x), + } + } + } + + /// Get the canonical declaration of this type, if it is available. + pub fn canonical_declaration(&self, + location: Option<&Cursor>) + -> Option { + let mut declaration = self.declaration(); + if !declaration.is_valid() { + if let Some(location) = location { + let mut location = *location; + if let Some(referenced) = location.referenced() { + location = referenced; + } + if location.is_template_like() { + declaration = location; + } + } + } + + let canonical = declaration.canonical(); + if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound { + Some(CanonicalTypeDeclaration(*self, canonical)) + } else { + None + } + } + + /// Get a raw display name for this type. + pub fn spelling(&self) -> String { + let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; + // Clang 5.0 introduced changes in the spelling API so it returned the + // full qualified name. Let's undo that here. + if s.split("::").all(|s| is_valid_identifier(s)) { + if let Some(s) = s.split("::").last() { + return s.to_owned(); + } + } + + s + } + + /// Is this type const qualified? + pub fn is_const(&self) -> bool { + unsafe { clang_isConstQualifiedType(self.x) != 0 } + } + + /// What is the size of this type? Paper over invalid types by returning `0` + /// for them. + pub fn size(&self) -> usize { + unsafe { + let val = clang_Type_getSizeOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the size of this type? + pub fn fallible_size(&self) -> Result { + let val = unsafe { clang_Type_getSizeOf(self.x) }; + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + + /// What is the alignment of this type? Paper over invalid types by + /// returning `0`. + pub fn align(&self) -> usize { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the alignment of this type? + pub fn fallible_align(&self) -> Result { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + } + + /// Get the layout for this type, or an error describing why it does not + /// have a valid layout. + pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { + use ir::layout::Layout; + let size = try!(self.fallible_size()); + let align = try!(self.fallible_align()); + Ok(Layout::new(size, align)) + } + + /// Get the number of template arguments this type has, or `None` if it is + /// not some kind of template. + pub fn num_template_args(&self) -> Option { + let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None + } + } + + /// If this type is a class template specialization, return its + /// template arguments. Otherwise, return None. + pub fn template_args(&self) -> Option { + self.num_template_args().map(|n| { + TypeTemplateArgIterator { + x: self.x, + length: n, + index: 0, + } + }) + } + + /// Given that this type is a pointer type, return the type that it points + /// to. + pub fn pointee_type(&self) -> Option { + match self.kind() { + CXType_Pointer | + CXType_RValueReference | + CXType_LValueReference | + CXType_MemberPointer | + CXType_ObjCObjectPointer => { + let ret = Type { + x: unsafe { clang_getPointeeType(self.x) }, + }; + debug_assert!(ret.is_valid()); + Some(ret) + } + _ => None, + } + } + + /// Given that this type is an array, vector, or complex type, return the + /// type of its elements. + pub fn elem_type(&self) -> Option { + let current_type = Type { + x: unsafe { clang_getElementType(self.x) }, + }; + if current_type.is_valid() { + Some(current_type) + } else { + None + } + } + + /// Given that this type is an array or vector type, return its number of + /// elements. + pub fn num_elements(&self) -> Option { + let num_elements_returned = unsafe { clang_getNumElements(self.x) }; + if num_elements_returned != -1 { + Some(num_elements_returned as usize) + } else { + None + } + } + + /// Get the canonical version of this type. This sees through `typdef`s and + /// aliases to get the underlying, canonical type. + pub fn canonical_type(&self) -> Type { + unsafe { + Type { + x: clang_getCanonicalType(self.x), + } + } + } + + /// Is this type a variadic function type? + pub fn is_variadic(&self) -> bool { + unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } + } + + /// Given that this type is a function type, get the type of its return + /// value. + pub fn ret_type(&self) -> Option { + let rt = Type { + x: unsafe { clang_getResultType(self.x) }, + }; + if rt.is_valid() { Some(rt) } else { None } + } + + /// Given that this type is a function type, get its calling convention. If + /// this is not a function type, `CXCallingConv_Invalid` is returned. + pub fn call_conv(&self) -> CXCallingConv { + unsafe { clang_getFunctionTypeCallingConv(self.x) } + } + + /// For elaborated types (types which use `class`, `struct`, or `union` to + /// disambiguate types from local bindings), get the underlying type. + pub fn named(&self) -> Type { + unsafe { + Type { + x: if clang_Type_getNamedType::is_loaded() { + clang_Type_getNamedType(self.x) + } else { + self.x + }, + } + } + } + + /// Is this a valid type? + pub fn is_valid(&self) -> bool { + self.kind() != CXType_Invalid + } + + /// Is this a valid and exposed type? + pub fn is_valid_and_exposed(&self) -> bool { + self.is_valid() && self.kind() != CXType_Unexposed + } + + /// Is this type a fully instantiated template? + pub fn is_fully_instantiated_template(&self) -> bool { + // Yep, the spelling of this containing type-parameter is extremely + // nasty... But can happen in . Unfortunately I couldn't + // reduce it enough :( + self.template_args().map_or(false, |args| args.len() > 0) && + match self.declaration().kind() { + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_TypeAliasTemplateDecl | + CXCursor_TemplateTemplateParameter => false, + _ => true, + } + } + + /// Is this type an associated template type? Eg `T::Associated` in + /// this example: + /// + /// ```c++ + /// template + /// class Foo { + /// typename T::Associated member; + /// }; + /// ``` + pub fn is_associated_type(&self) -> bool { + // This is terrible :( + fn hacky_parse_associated_type>(spelling: S) -> bool { + lazy_static! { + static ref ASSOC_TYPE_RE: regex::Regex = + regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap(); + } + ASSOC_TYPE_RE.is_match(spelling.as_ref()) + } + + self.kind() == CXType_Unexposed && + (hacky_parse_associated_type(self.spelling()) || + hacky_parse_associated_type(self.canonical_type().spelling())) + } +} + +/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its +/// cursor is the canonical declaration for its type. If you have a +/// `CanonicalTypeDeclaration` instance, you know for sure that the type and +/// cursor match up in a canonical declaration relationship, and it simply +/// cannot be otherwise. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CanonicalTypeDeclaration(Type, Cursor); + +impl CanonicalTypeDeclaration { + /// Get the type. + pub fn ty(&self) -> &Type { + &self.0 + } + + /// Get the type's canonical declaration cursor. + pub fn cursor(&self) -> &Cursor { + &self.1 + } +} + +/// An iterator for a type's template arguments. +pub struct TypeTemplateArgIterator { + x: CXType, + length: u32, + index: u32, +} + +impl Iterator for TypeTemplateArgIterator { + type Item = Type; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index as c_uint; + self.index += 1; + Some(Type { + x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, + }) + } else { + None + } + } +} + +impl ExactSizeIterator for TypeTemplateArgIterator { + fn len(&self) -> usize { + assert!(self.index <= self.length); + (self.length - self.index) as usize + } +} + +/// A `SourceLocation` is a file, line, column, and byte offset location for +/// some source text. +pub struct SourceLocation { + x: CXSourceLocation, +} + +impl SourceLocation { + /// Get the (file, line, column, byte offset) tuple for this source + /// location. + pub fn location(&self) -> (File, usize, usize, usize) { + unsafe { + let mut file = mem::zeroed(); + let mut line = 0; + let mut col = 0; + let mut off = 0; + clang_getSpellingLocation(self.x, + &mut file, + &mut line, + &mut col, + &mut off); + (File { + x: file, + }, + line as usize, + col as usize, + off as usize) + } + } +} + +impl fmt::Display for SourceLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (file, line, col, _) = self.location(); + if let Some(name) = file.name() { + write!(f, "{}:{}:{}", name, line, col) + } else { + "builtin definitions".fmt(f) + } + } +} + +/// A comment in the source text. +/// +/// Comments are sort of parsed by Clang, and have a tree structure. +pub struct Comment { + x: CXComment, +} + +impl Comment { + /// What kind of comment is this? + pub fn kind(&self) -> CXCommentKind { + unsafe { clang_Comment_getKind(self.x) } + } + + /// Get this comment's children comment + pub fn get_children(&self) -> CommentChildrenIterator { + CommentChildrenIterator { + parent: self.x, + length: unsafe { clang_Comment_getNumChildren(self.x) }, + index: 0, + } + } + + /// Given that this comment is the start or end of an HTML tag, get its tag + /// name. + pub fn get_tag_name(&self) -> String { + unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } + } + + /// Given that this comment is an HTML start tag, get its attributes. + pub fn get_tag_attrs(&self) -> CommentAttributesIterator { + CommentAttributesIterator { + x: self.x, + length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, + index: 0, + } + } +} + +/// An iterator for a comment's children +pub struct CommentChildrenIterator { + parent: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentChildrenIterator { + type Item = Comment; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(Comment { + x: unsafe { clang_Comment_getChild(self.parent, idx) }, + }) + } else { + None + } + } +} + +/// An HTML start tag comment attribute +pub struct CommentAttribute { + /// HTML start tag attribute name + pub name: String, + /// HTML start tag attribute value + pub value: String, +} + +/// An iterator for a comment's attributes +pub struct CommentAttributesIterator { + x: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentAttributesIterator { + type Item = CommentAttribute; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(CommentAttribute { + name: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrName(self.x, idx)) + }, + value: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrValue(self.x, idx)) + }, + }) + } else { + None + } + } +} + +/// A source file. +pub struct File { + x: CXFile, +} + +impl File { + /// Get the name of this source file. + pub fn name(&self) -> Option { + if self.x.is_null() { + return None; + } + Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) + } +} + +fn cxstring_into_string(s: CXString) -> String { + if s.data.is_null() { + return "".to_owned(); + } + unsafe { + let c_str = CStr::from_ptr(clang_getCString(s) as *const _); + let ret = c_str.to_string_lossy().into_owned(); + clang_disposeString(s); + ret + } +} + +/// An `Index` is an environment for a set of translation units that will +/// typically end up linked together in one final binary. +pub struct Index { + x: CXIndex, +} + +impl Index { + /// Construct a new `Index`. + /// + /// The `pch` parameter controls whether declarations in pre-compiled + /// headers are included when enumerating a translation unit's "locals". + /// + /// The `diag` parameter controls whether debugging diagnostics are enabled. + pub fn new(pch: bool, diag: bool) -> Index { + unsafe { + Index { + x: clang_createIndex(pch as c_int, diag as c_int), + } + } + } +} + +impl fmt::Debug for Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Index {{ }}") + } +} + +impl Drop for Index { + fn drop(&mut self) { + unsafe { + clang_disposeIndex(self.x); + } + } +} + +/// A token emitted by clang's lexer. +#[derive(Debug)] +pub struct Token { + /// The kind of token this is. + pub kind: CXTokenKind, + /// A display name for this token. + pub spelling: String, +} + +/// A translation unit (or "compilation unit"). +pub struct TranslationUnit { + x: CXTranslationUnit, +} + +impl fmt::Debug for TranslationUnit { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "TranslationUnit {{ }}") + } +} + +impl TranslationUnit { + /// Parse a source file into a translation unit. + pub fn parse(ix: &Index, + file: &str, + cmd_args: &[String], + unsaved: &[UnsavedFile], + opts: CXTranslationUnit_Flags) + -> Option { + let fname = CString::new(file).unwrap(); + let _c_args: Vec = + cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect(); + let c_args: Vec<*const c_char> = + _c_args.iter().map(|s| s.as_ptr()).collect(); + let mut c_unsaved: Vec = + unsaved.iter().map(|f| f.x).collect(); + let tu = unsafe { + clang_parseTranslationUnit(ix.x, + fname.as_ptr(), + c_args.as_ptr(), + c_args.len() as c_int, + c_unsaved.as_mut_ptr(), + c_unsaved.len() as c_uint, + opts) + }; + if tu.is_null() { + None + } else { + Some(TranslationUnit { + x: tu, + }) + } + } + + /// Get the Clang diagnostic information associated with this translation + /// unit. + pub fn diags(&self) -> Vec { + unsafe { + let num = clang_getNumDiagnostics(self.x) as usize; + let mut diags = vec![]; + for i in 0..num { + diags.push(Diagnostic { + x: clang_getDiagnostic(self.x, i as c_uint), + }); + } + diags + } + } + + /// Get a cursor pointing to the root of this translation unit's AST. + pub fn cursor(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTranslationUnitCursor(self.x), + } + } + } + + /// Is this the null translation unit? + pub fn is_null(&self) -> bool { + self.x.is_null() + } + + /// Invoke Clang's lexer on this translation unit and get the stream of + /// tokens that come out. + pub fn tokens(&self, cursor: &Cursor) -> Option> { + let range = cursor.extent(); + let mut tokens = vec![]; + unsafe { + let mut token_ptr = ptr::null_mut(); + let mut num_tokens: c_uint = 0; + clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens); + if token_ptr.is_null() { + return None; + } + + let token_array = slice::from_raw_parts(token_ptr, + num_tokens as usize); + for &token in token_array.iter() { + let kind = clang_getTokenKind(token); + let spelling = + cxstring_into_string(clang_getTokenSpelling(self.x, token)); + + tokens.push(Token { + kind: kind, + spelling: spelling, + }); + } + clang_disposeTokens(self.x, token_ptr, num_tokens); + } + Some(tokens) + } + + /// Convert a set of tokens from clang into `cexpr` tokens, for further + /// processing. + pub fn cexpr_tokens(&self, + cursor: &Cursor) + -> Option> { + use cexpr::token; + + let mut tokens = match self.tokens(cursor) { + Some(tokens) => tokens, + None => return None, + }; + + // FIXME(emilio): LLVM 3.9 at least always include an extra token for no + // good reason (except if we're at EOF). So we do this kind of hack, + // where we skip known-to-cause problems trailing punctuation and + // trailing keywords. + // + // This is sort of unfortunate, though :(. + // + // I'll try to get it fixed in LLVM if I have the time to submit a + // patch. + let mut trim_last_token = false; + if let Some(token) = tokens.last() { + // The starting of the next macro. + trim_last_token |= token.spelling == "#" && + token.kind == CXToken_Punctuation; + + // A following keyword of any kind, like a following declaration. + trim_last_token |= token.kind == CXToken_Keyword; + } + + if trim_last_token { + tokens.pop().unwrap(); + } + + Some(tokens.into_iter() + .filter_map(|token| { + let kind = match token.kind { + CXToken_Punctuation => token::Kind::Punctuation, + CXToken_Literal => token::Kind::Literal, + CXToken_Identifier => token::Kind::Identifier, + CXToken_Keyword => token::Kind::Keyword, + // NB: cexpr is not too happy about comments inside + // expressions, so we strip them down here. + CXToken_Comment => return None, + _ => { + panic!("Found unexpected token kind: {:?}", token.kind) + } + }; + + Some(token::Token { + kind: kind, + raw: token.spelling.into_bytes().into_boxed_slice(), + }) + }) + .collect::>()) + } +} + +impl Drop for TranslationUnit { + fn drop(&mut self) { + unsafe { + clang_disposeTranslationUnit(self.x); + } + } +} + + +/// A diagnostic message generated while parsing a translation unit. +pub struct Diagnostic { + x: CXDiagnostic, +} + +impl Diagnostic { + /// Format this diagnostic message as a string, using the given option bit + /// flags. + pub fn format(&self) -> String { + unsafe { + let opts = clang_defaultDiagnosticDisplayOptions(); + cxstring_into_string(clang_formatDiagnostic(self.x, opts)) + } + } + + /// What is the severity of this diagnostic message? + pub fn severity(&self) -> CXDiagnosticSeverity { + unsafe { clang_getDiagnosticSeverity(self.x) } + } +} + +impl Drop for Diagnostic { + /// Destroy this diagnostic message. + fn drop(&mut self) { + unsafe { + clang_disposeDiagnostic(self.x); + } + } +} + +/// A file which has not been saved to disk. +pub struct UnsavedFile { + x: CXUnsavedFile, + /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in + /// `CXUnsavedFile`. + pub name: CString, + contents: CString, +} + +impl UnsavedFile { + /// Construct a new unsaved file with the given `name` and `contents`. + pub fn new(name: &str, contents: &str) -> UnsavedFile { + let name = CString::new(name).unwrap(); + let contents = CString::new(contents).unwrap(); + let x = CXUnsavedFile { + Filename: name.as_ptr(), + Contents: contents.as_ptr(), + Length: contents.as_bytes().len() as c_ulong, + }; + UnsavedFile { + x: x, + name: name, + contents: contents, + } + } +} + +impl fmt::Debug for UnsavedFile { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "UnsavedFile(name: {:?}, contents: {:?})", + self.name, + self.contents) + } +} + +/// Convert a cursor kind into a static string. +pub fn kind_to_str(x: CXCursorKind) -> String { + unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } +} + +/// Convert a type kind to a static string. +pub fn type_to_str(x: CXTypeKind) -> String { + unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } +} + +/// Dump the Clang AST to stdout for debugging purposes. +pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { + fn print_indent>(depth: isize, s: S) { + for _ in 0..depth { + print!(" "); + } + println!("{}", s.as_ref()); + } + + fn print_cursor>(depth: isize, prefix: S, c: &Cursor) { + let prefix = prefix.as_ref(); + print_indent(depth, + format!(" {}kind = {}", prefix, kind_to_str(c.kind()))); + print_indent(depth, + format!(" {}spelling = \"{}\"", prefix, c.spelling())); + print_indent(depth, format!(" {}location = {}", prefix, c.location())); + print_indent(depth, + format!(" {}is-definition? {}", + prefix, + c.is_definition())); + print_indent(depth, + format!(" {}is-declaration? {}", + prefix, + c.is_declaration())); + print_indent(depth, + format!(" {}is-inlined-function? {}", + prefix, + c.is_inlined_function())); + + let templ_kind = c.template_kind(); + if templ_kind != CXCursor_NoDeclFound { + print_indent(depth, + format!(" {}template-kind = {}", + prefix, + kind_to_str(templ_kind))); + } + if let Some(usr) = c.usr() { + print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); + } + if let Ok(num) = c.num_args() { + print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); + } + if let Some(num) = c.num_template_args() { + print_indent(depth, + format!(" {}number-of-template-args = {}", + prefix, + num)); + } + if let Some(width) = c.bit_width() { + print_indent(depth, format!(" {}bit-width = {}", prefix, width)); + } + if let Some(ty) = c.enum_type() { + print_indent(depth, + format!(" {}enum-type = {}", + prefix, + type_to_str(ty.kind()))); + } + if let Some(val) = c.enum_val_signed() { + print_indent(depth, format!(" {}enum-val = {}", prefix, val)); + } + if let Some(ty) = c.typedef_type() { + print_indent(depth, + format!(" {}typedef-type = {}", + prefix, + type_to_str(ty.kind()))); + } + if let Some(ty) = c.ret_type() { + print_indent(depth, + format!(" {}ret-type = {}", + prefix, + type_to_str(ty.kind()))); + } + + if let Some(refd) = c.referenced() { + if refd != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "referenced.", + &refd); + } + } + + let canonical = c.canonical(); + if canonical != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "canonical.", + &canonical); + } + + if let Some(specialized) = c.specialized() { + if specialized != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "specialized.", + &specialized); + } + } + + if let Some(parent) = c.fallible_semantic_parent() { + println!(""); + print_cursor(depth, + String::from(prefix) + "semantic-parent.", + &parent); + } + } + + fn print_type>(depth: isize, prefix: S, ty: &Type) { + let prefix = prefix.as_ref(); + + let kind = ty.kind(); + print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); + if kind == CXType_Invalid { + return; + } + + print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); + + print_indent(depth, + format!(" {}spelling = \"{}\"", prefix, ty.spelling())); + let num_template_args = + unsafe { clang_Type_getNumTemplateArguments(ty.x) }; + if num_template_args >= 0 { + print_indent(depth, + format!(" {}number-of-template-args = {}", + prefix, + num_template_args)); + } + if let Some(num) = ty.num_elements() { + print_indent(depth, + format!(" {}number-of-elements = {}", prefix, num)); + } + print_indent(depth, + format!(" {}is-variadic? {}", prefix, ty.is_variadic())); + + let canonical = ty.canonical_type(); + if canonical != *ty { + println!(""); + print_type(depth, String::from(prefix) + "canonical.", &canonical); + } + + if let Some(pointee) = ty.pointee_type() { + if pointee != *ty { + println!(""); + print_type(depth, String::from(prefix) + "pointee.", &pointee); + } + } + + if let Some(elem) = ty.elem_type() { + if elem != *ty { + println!(""); + print_type(depth, String::from(prefix) + "elements.", &elem); + } + } + + if let Some(ret) = ty.ret_type() { + if ret != *ty { + println!(""); + print_type(depth, String::from(prefix) + "return.", &ret); + } + } + + let named = ty.named(); + if named != *ty && named.is_valid() { + println!(""); + print_type(depth, String::from(prefix) + "named.", &named); + } + } + + print_indent(depth, "("); + print_cursor(depth, "", c); + + println!(""); + let ty = c.cur_type(); + print_type(depth, "type.", &ty); + + let declaration = ty.declaration(); + if declaration != *c && declaration.kind() != CXCursor_NoDeclFound { + println!(""); + print_cursor(depth, "type.declaration.", &declaration); + } + + // Recurse. + let mut found_children = false; + c.visit(|s| { + if !found_children { + println!(""); + found_children = true; + } + ast_dump(&s, depth + 1) + }); + + print_indent(depth, ")"); + + CXChildVisit_Continue +} + +/// Try to extract the clang version to a string +pub fn extract_clang_version() -> String { + unsafe { cxstring_into_string(clang_getClangVersion()) } +} + +/// A wrapper for the result of evaluating an expression. +#[derive(Debug)] +pub struct EvalResult { + x: CXEvalResult, +} + +impl EvalResult { + /// Evaluate `cursor` and return the result. + pub fn new(cursor: Cursor) -> Option { + if !clang_Cursor_Evaluate::is_loaded() { + return None; + } + + // Clang has an internal assertion we can trigger if we try to evaluate + // a cursor containing a variadic template type reference. Triggering + // the assertion aborts the process, and we don't want that. Clang + // *also* doesn't expose any API for finding variadic vs non-variadic + // template type references, let alone whether a type referenced is a + // template type, instead they seem to show up as type references to an + // unexposed type. Our solution is to just flat out ban all + // `CXType_Unexposed` from evaluation. + let mut found_cant_eval = false; + cursor.visit(|c| if c.kind() == CXCursor_TypeRef && + c.cur_type().kind() == CXType_Unexposed { + found_cant_eval = true; + CXChildVisit_Break + } else { + CXChildVisit_Recurse + }); + if found_cant_eval { + return None; + } + + Some(EvalResult { + x: unsafe { clang_Cursor_Evaluate(cursor.x) }, + }) + } + + fn kind(&self) -> CXEvalResultKind { + unsafe { clang_EvalResult_getKind(self.x) } + } + + /// Try to get back the result as a double. + pub fn as_double(&self) -> Option { + match self.kind() { + CXEval_Float => { + Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) + } + _ => None, + } + } + + /// Try to get back the result as an integer. + pub fn as_int(&self) -> Option { + match self.kind() { + CXEval_Int => { + Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32) + } + _ => None, + } + } + + /// Evaluates the expression as a literal string, that may or may not be + /// valid utf-8. + pub fn as_literal_string(&self) -> Option> { + match self.kind() { + CXEval_StrLiteral => { + let ret = unsafe { + CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) + }; + Some(ret.to_bytes().to_vec()) + } + _ => None, + } + } +} + +impl Drop for EvalResult { + fn drop(&mut self) { + unsafe { clang_EvalResult_dispose(self.x) }; + } +} diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index e64354fb9d..a55e2a42bc 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -1,190 +1,190 @@ -//! Intermediate representation for C/C++ enumerations. - -use super::context::{BindgenContext, ItemId}; -use super::item::Item; -use super::ty::TypeKind; -use clang; -use ir::annotations::Annotations; -use parse::{ClangItemParser, ParseError}; - -/// An enum representing custom handling that can be given to a variant. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum EnumVariantCustomBehavior { - /// This variant will be constified, that is, forced to generate a constant. - Constify, - /// This variant will be hidden entirely from the resulting enum. - Hide, -} - -/// A C/C++ enumeration. -#[derive(Debug)] -pub struct Enum { - /// The representation used for this enum; it should be an `IntKind` type or - /// an alias to one. - /// - /// It's `None` if the enum is a forward declaration and isn't defined - /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. - repr: Option, - - /// The different variants, with explicit values. - variants: Vec, -} - -impl Enum { - /// Construct a new `Enum` with the given representation and variants. - pub fn new(repr: Option, variants: Vec) -> Self { - Enum { - repr: repr, - variants: variants, - } - } - - /// Get this enumeration's representation. - pub fn repr(&self) -> Option { - self.repr - } - - /// Get this enumeration's variants. - pub fn variants(&self) -> &[EnumVariant] { - &self.variants - } - - /// Construct an enumeration from the given Clang type. - pub fn from_ty(ty: &clang::Type, - ctx: &mut BindgenContext) - -> Result { - use clang_sys::*; - debug!("Enum::from_ty {:?}", ty); - - if ty.kind() != CXType_Enum { - return Err(ParseError::Continue); - } - - let declaration = ty.declaration().canonical(); - let repr = declaration.enum_type() - .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); - let mut variants = vec![]; - - // Assume signedness since the default type by the C standard is an int. - let is_signed = - repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) - .map_or(true, |ty| match *ty.kind() { - TypeKind::Int(ref int_kind) => int_kind.is_signed(), - ref other => { - panic!("Since when enums can be non-integers? {:?}", - other) - } - }); - - let type_name = ty.spelling(); - let type_name = if type_name.is_empty() { - None - } else { - Some(type_name) - }; - let type_name = type_name.as_ref().map(String::as_str); - - let definition = declaration.definition().unwrap_or(declaration); - definition.visit(|cursor| { - if cursor.kind() == CXCursor_EnumConstantDecl { - let value = if is_signed { - cursor.enum_val_signed().map(EnumVariantValue::Signed) - } else { - cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) - }; - if let Some(val) = value { - let name = cursor.spelling(); - let custom_behavior = ctx.parse_callbacks() - .and_then(|t| { - t.enum_variant_behavior(type_name, &name, val) - }) - .or_else(|| { - Annotations::new(&cursor) - .and_then(|anno| if anno.hide() { - Some(EnumVariantCustomBehavior::Hide) - } else if - anno.constify_enum_variant() { - Some(EnumVariantCustomBehavior::Constify) - } else { - None - }) - }); - - let comment = cursor.raw_comment(); - variants.push(EnumVariant::new(name, - comment, - val, - custom_behavior)); - } - } - CXChildVisit_Continue - }); - Ok(Enum::new(repr, variants)) - } -} - -/// A single enum variant, to be contained only in an enum. -#[derive(Debug)] -pub struct EnumVariant { - /// The name of the variant. - name: String, - - /// An optional doc comment. - comment: Option, - - /// The integer value of the variant. - val: EnumVariantValue, - - /// The custom behavior this variant may have, if any. - custom_behavior: Option, -} - -/// A constant value assigned to an enumeration variant. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EnumVariantValue { - /// A signed constant. - Signed(i64), - - /// An unsigned constant. - Unsigned(u64), -} - -impl EnumVariant { - /// Construct a new enumeration variant from the given parts. - pub fn new(name: String, - comment: Option, - val: EnumVariantValue, - custom_behavior: Option) - -> Self { - EnumVariant { - name: name, - comment: comment, - val: val, - custom_behavior: custom_behavior, - } - } - - /// Get this variant's name. - pub fn name(&self) -> &str { - &self.name - } - - /// Get this variant's value. - pub fn val(&self) -> EnumVariantValue { - self.val - } - - /// Returns whether this variant should be enforced to be a constant by code - /// generation. - pub fn force_constification(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) - } - - /// Returns whether the current variant should be hidden completely from the - /// resulting rust enum. - pub fn hidden(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) - } -} +//! Intermediate representation for C/C++ enumerations. + +use super::context::{BindgenContext, ItemId}; +use super::item::Item; +use super::ty::TypeKind; +use clang; +use ir::annotations::Annotations; +use parse::{ClangItemParser, ParseError}; + +/// An enum representing custom handling that can be given to a variant. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum EnumVariantCustomBehavior { + /// This variant will be constified, that is, forced to generate a constant. + Constify, + /// This variant will be hidden entirely from the resulting enum. + Hide, +} + +/// A C/C++ enumeration. +#[derive(Debug)] +pub struct Enum { + /// The representation used for this enum; it should be an `IntKind` type or + /// an alias to one. + /// + /// It's `None` if the enum is a forward declaration and isn't defined + /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. + repr: Option, + + /// The different variants, with explicit values. + variants: Vec, +} + +impl Enum { + /// Construct a new `Enum` with the given representation and variants. + pub fn new(repr: Option, variants: Vec) -> Self { + Enum { + repr: repr, + variants: variants, + } + } + + /// Get this enumeration's representation. + pub fn repr(&self) -> Option { + self.repr + } + + /// Get this enumeration's variants. + pub fn variants(&self) -> &[EnumVariant] { + &self.variants + } + + /// Construct an enumeration from the given Clang type. + pub fn from_ty(ty: &clang::Type, + ctx: &mut BindgenContext) + -> Result { + use clang_sys::*; + debug!("Enum::from_ty {:?}", ty); + + if ty.kind() != CXType_Enum { + return Err(ParseError::Continue); + } + + let declaration = ty.declaration().canonical(); + let repr = declaration.enum_type() + .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); + let mut variants = vec![]; + + // Assume signedness since the default type by the C standard is an int. + let is_signed = + repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) + .map_or(true, |ty| match *ty.kind() { + TypeKind::Int(ref int_kind) => int_kind.is_signed(), + ref other => { + panic!("Since when enums can be non-integers? {:?}", + other) + } + }); + + let type_name = ty.spelling(); + let type_name = if type_name.is_empty() { + None + } else { + Some(type_name) + }; + let type_name = type_name.as_ref().map(String::as_str); + + let definition = declaration.definition().unwrap_or(declaration); + definition.visit(|cursor| { + if cursor.kind() == CXCursor_EnumConstantDecl { + let value = if is_signed { + cursor.enum_val_signed().map(EnumVariantValue::Signed) + } else { + cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) + }; + if let Some(val) = value { + let name = cursor.spelling(); + let custom_behavior = ctx.parse_callbacks() + .and_then(|t| { + t.enum_variant_behavior(type_name, &name, val) + }) + .or_else(|| { + Annotations::new(&cursor) + .and_then(|anno| if anno.hide() { + Some(EnumVariantCustomBehavior::Hide) + } else if + anno.constify_enum_variant() { + Some(EnumVariantCustomBehavior::Constify) + } else { + None + }) + }); + + let comment = cursor.raw_comment(); + variants.push(EnumVariant::new(name, + comment, + val, + custom_behavior)); + } + } + CXChildVisit_Continue + }); + Ok(Enum::new(repr, variants)) + } +} + +/// A single enum variant, to be contained only in an enum. +#[derive(Debug)] +pub struct EnumVariant { + /// The name of the variant. + name: String, + + /// An optional doc comment. + comment: Option, + + /// The integer value of the variant. + val: EnumVariantValue, + + /// The custom behavior this variant may have, if any. + custom_behavior: Option, +} + +/// A constant value assigned to an enumeration variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EnumVariantValue { + /// A signed constant. + Signed(i64), + + /// An unsigned constant. + Unsigned(u64), +} + +impl EnumVariant { + /// Construct a new enumeration variant from the given parts. + pub fn new(name: String, + comment: Option, + val: EnumVariantValue, + custom_behavior: Option) + -> Self { + EnumVariant { + name: name, + comment: comment, + val: val, + custom_behavior: custom_behavior, + } + } + + /// Get this variant's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variant's value. + pub fn val(&self) -> EnumVariantValue { + self.val + } + + /// Returns whether this variant should be enforced to be a constant by code + /// generation. + pub fn force_constification(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) + } + + /// Returns whether the current variant should be hidden completely from the + /// resulting rust enum. + pub fn hidden(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) + } +} diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs index 419f9d4421..36fe5f37a9 100644 --- a/src/ir/item_kind.rs +++ b/src/ir/item_kind.rs @@ -1,147 +1,147 @@ -//! Different variants of an `Item` in our intermediate representation. - -use super::context::BindgenContext; -use super::dot::DotAttributes; -use super::function::Function; -use super::module::Module; -use super::ty::Type; -use super::var::Var; -use std::io; - -/// A item we parse and translate. -#[derive(Debug)] -pub enum ItemKind { - /// A module, created implicitly once (the root module), or via C++ - /// namespaces. - Module(Module), - - /// A type declared in any of the multiple ways it can be declared. - Type(Type), - - /// A function or method declaration. - Function(Function), - - /// A variable declaration, most likely a static. - Var(Var), -} - -impl ItemKind { - /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it - /// is some other kind. - pub fn as_module(&self) -> Option<&Module> { - match *self { - ItemKind::Module(ref module) => Some(module), - _ => None, - } - } - - /// Transform our `ItemKind` into a string. - pub fn kind_name(&self) -> &'static str { - match *self { - ItemKind::Module(..) => "Module", - ItemKind::Type(..) => "Type", - ItemKind::Function(..) => "Function", - ItemKind::Var(..) => "Var", - } - } - - /// Is this a module? - pub fn is_module(&self) -> bool { - self.as_module().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it - /// is some other kind. - pub fn expect_module(&self) -> &Module { - self.as_module().expect("Not a module") - } - - /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if - /// it is some other kind. - pub fn as_function(&self) -> Option<&Function> { - match *self { - ItemKind::Function(ref func) => Some(func), - _ => None, - } - } - - /// Is this a function? - pub fn is_function(&self) -> bool { - self.as_function().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Function`, or panic if - /// it is some other kind. - pub fn expect_function(&self) -> &Function { - self.as_function().expect("Not a function") - } - - /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if - /// it is some other kind. - pub fn as_type(&self) -> Option<&Type> { - match *self { - ItemKind::Type(ref ty) => Some(ty), - _ => None, - } - } - - /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` - /// if it is some other kind. - pub fn as_type_mut(&mut self) -> Option<&mut Type> { - match *self { - ItemKind::Type(ref mut ty) => Some(ty), - _ => None, - } - } - - /// Is this a type? - pub fn is_type(&self) -> bool { - self.as_type().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is - /// some other kind. - pub fn expect_type(&self) -> &Type { - self.as_type().expect("Not a type") - } - - /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is - /// some other kind. - pub fn as_var(&self) -> Option<&Var> { - match *self { - ItemKind::Var(ref v) => Some(v), - _ => None, - } - } - - /// Is this a variable? - pub fn is_var(&self) -> bool { - self.as_var().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is - /// some other kind. - pub fn expect_var(&self) -> &Var { - self.as_var().expect("Not a var") - } -} - -impl DotAttributes for ItemKind { - fn dot_attributes(&self, - ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - try!(writeln!(out, - "kind{}", - self.kind_name())); - - match *self { - ItemKind::Module(ref module) => module.dot_attributes(ctx, out), - ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out), - ItemKind::Function(ref func) => func.dot_attributes(ctx, out), - ItemKind::Var(ref var) => var.dot_attributes(ctx, out), - } - } -} +//! Different variants of an `Item` in our intermediate representation. + +use super::context::BindgenContext; +use super::dot::DotAttributes; +use super::function::Function; +use super::module::Module; +use super::ty::Type; +use super::var::Var; +use std::io; + +/// A item we parse and translate. +#[derive(Debug)] +pub enum ItemKind { + /// A module, created implicitly once (the root module), or via C++ + /// namespaces. + Module(Module), + + /// A type declared in any of the multiple ways it can be declared. + Type(Type), + + /// A function or method declaration. + Function(Function), + + /// A variable declaration, most likely a static. + Var(Var), +} + +impl ItemKind { + /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it + /// is some other kind. + pub fn as_module(&self) -> Option<&Module> { + match *self { + ItemKind::Module(ref module) => Some(module), + _ => None, + } + } + + /// Transform our `ItemKind` into a string. + pub fn kind_name(&self) -> &'static str { + match *self { + ItemKind::Module(..) => "Module", + ItemKind::Type(..) => "Type", + ItemKind::Function(..) => "Function", + ItemKind::Var(..) => "Var", + } + } + + /// Is this a module? + pub fn is_module(&self) -> bool { + self.as_module().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it + /// is some other kind. + pub fn expect_module(&self) -> &Module { + self.as_module().expect("Not a module") + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if + /// it is some other kind. + pub fn as_function(&self) -> Option<&Function> { + match *self { + ItemKind::Function(ref func) => Some(func), + _ => None, + } + } + + /// Is this a function? + pub fn is_function(&self) -> bool { + self.as_function().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or panic if + /// it is some other kind. + pub fn expect_function(&self) -> &Function { + self.as_function().expect("Not a function") + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if + /// it is some other kind. + pub fn as_type(&self) -> Option<&Type> { + match *self { + ItemKind::Type(ref ty) => Some(ty), + _ => None, + } + } + + /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` + /// if it is some other kind. + pub fn as_type_mut(&mut self) -> Option<&mut Type> { + match *self { + ItemKind::Type(ref mut ty) => Some(ty), + _ => None, + } + } + + /// Is this a type? + pub fn is_type(&self) -> bool { + self.as_type().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is + /// some other kind. + pub fn expect_type(&self) -> &Type { + self.as_type().expect("Not a type") + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is + /// some other kind. + pub fn as_var(&self) -> Option<&Var> { + match *self { + ItemKind::Var(ref v) => Some(v), + _ => None, + } + } + + /// Is this a variable? + pub fn is_var(&self) -> bool { + self.as_var().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is + /// some other kind. + pub fn expect_var(&self) -> &Var { + self.as_var().expect("Not a var") + } +} + +impl DotAttributes for ItemKind { + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + try!(writeln!(out, + "kind{}", + self.kind_name())); + + match *self { + ItemKind::Module(ref module) => module.dot_attributes(ctx, out), + ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out), + ItemKind::Function(ref func) => func.dot_attributes(ctx, out), + ItemKind::Var(ref var) => var.dot_attributes(ctx, out), + } + } +} diff --git a/src/ir/layout.rs b/src/ir/layout.rs index 21382b2d99..58d6dc615f 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -1,134 +1,134 @@ -//! Intermediate representation for the physical layout of some type. - -use super::context::BindgenContext; -use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; -use clang; -use std::{cmp, mem}; - -/// A type that represents the struct layout of a type. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Layout { - /// The size (in bytes) of this layout. - pub size: usize, - /// The alignment (in bytes) of this layout. - pub align: usize, - /// Whether this layout's members are packed or not. - pub packed: bool, -} - -#[test] -fn test_layout_for_size() { - let ptr_size = mem::size_of::<*mut ()>(); - assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size)); - assert_eq!(Layout::for_size(3 * ptr_size), - Layout::new(3 * ptr_size, ptr_size)); -} - -impl Layout { - /// Construct a new `Layout` with the given `size` and `align`. It is not - /// packed. - pub fn new(size: usize, align: usize) -> Self { - Layout { - size: size, - align: align, - packed: false, - } - } - - /// Creates a non-packed layout for a given size, trying to use the maximum - /// alignment possible. - pub fn for_size(size: usize) -> Self { - let mut next_align = 2; - while size % next_align == 0 && - next_align <= mem::size_of::<*mut ()>() { - next_align *= 2; - } - Layout { - size: size, - align: next_align / 2, - packed: false, - } - } - - /// Is this a zero-sized layout? - pub fn is_zero(&self) -> bool { - self.size == 0 && self.align == 0 - } - - /// Construct a zero-sized layout. - pub fn zero() -> Self { - Self::new(0, 0) - } - - /// Get this layout as an opaque type. - pub fn opaque(&self) -> Opaque { - Opaque(*self) - } -} - -/// When we are treating a type as opaque, it is just a blob with a `Layout`. -#[derive(Clone, Debug, PartialEq)] -pub struct Opaque(pub Layout); - -impl Opaque { - /// Construct a new opaque type from the given clang type. - pub fn from_clang_ty(ty: &clang::Type) -> Type { - let layout = Layout::new(ty.size(), ty.align()); - let ty_kind = TypeKind::Opaque; - Type::new(None, Some(layout), ty_kind, false) - } - - /// Return the known rust type we should use to create a correctly-aligned - /// field with this layout. - pub fn known_rust_type_for_array(&self) -> Option<&'static str> { - Some(match self.0.align { - 8 => "u64", - 4 => "u32", - 2 => "u16", - 1 => "u8", - _ => return None, - }) - } - - /// Return the array size that an opaque type for this layout should have if - /// we know the correct type for it, or `None` otherwise. - pub fn array_size(&self) -> Option { - if self.known_rust_type_for_array().is_some() { - Some(self.0.size / cmp::max(self.0.align, 1)) - } else { - None - } - } -} - -impl CanDeriveDebug for Opaque { - type Extra = (); - - fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } -} - -impl CanDeriveDefault for Opaque { - type Extra = (); - - fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } -} - -impl<'a> CanDeriveCopy<'a> for Opaque { - type Extra = (); - - fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } - - fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { - self.can_derive_copy(ctx, ()) - } -} +//! Intermediate representation for the physical layout of some type. + +use super::context::BindgenContext; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; +use clang; +use std::{cmp, mem}; + +/// A type that represents the struct layout of a type. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Layout { + /// The size (in bytes) of this layout. + pub size: usize, + /// The alignment (in bytes) of this layout. + pub align: usize, + /// Whether this layout's members are packed or not. + pub packed: bool, +} + +#[test] +fn test_layout_for_size() { + let ptr_size = mem::size_of::<*mut ()>(); + assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size)); + assert_eq!(Layout::for_size(3 * ptr_size), + Layout::new(3 * ptr_size, ptr_size)); +} + +impl Layout { + /// Construct a new `Layout` with the given `size` and `align`. It is not + /// packed. + pub fn new(size: usize, align: usize) -> Self { + Layout { + size: size, + align: align, + packed: false, + } + } + + /// Creates a non-packed layout for a given size, trying to use the maximum + /// alignment possible. + pub fn for_size(size: usize) -> Self { + let mut next_align = 2; + while size % next_align == 0 && + next_align <= mem::size_of::<*mut ()>() { + next_align *= 2; + } + Layout { + size: size, + align: next_align / 2, + packed: false, + } + } + + /// Is this a zero-sized layout? + pub fn is_zero(&self) -> bool { + self.size == 0 && self.align == 0 + } + + /// Construct a zero-sized layout. + pub fn zero() -> Self { + Self::new(0, 0) + } + + /// Get this layout as an opaque type. + pub fn opaque(&self) -> Opaque { + Opaque(*self) + } +} + +/// When we are treating a type as opaque, it is just a blob with a `Layout`. +#[derive(Clone, Debug, PartialEq)] +pub struct Opaque(pub Layout); + +impl Opaque { + /// Construct a new opaque type from the given clang type. + pub fn from_clang_ty(ty: &clang::Type) -> Type { + let layout = Layout::new(ty.size(), ty.align()); + let ty_kind = TypeKind::Opaque; + Type::new(None, Some(layout), ty_kind, false) + } + + /// Return the known rust type we should use to create a correctly-aligned + /// field with this layout. + pub fn known_rust_type_for_array(&self) -> Option<&'static str> { + Some(match self.0.align { + 8 => "u64", + 4 => "u32", + 2 => "u16", + 1 => "u8", + _ => return None, + }) + } + + /// Return the array size that an opaque type for this layout should have if + /// we know the correct type for it, or `None` otherwise. + pub fn array_size(&self) -> Option { + if self.known_rust_type_for_array().is_some() { + Some(self.0.size / cmp::max(self.0.align, 1)) + } else { + None + } + } +} + +impl CanDeriveDebug for Opaque { + type Extra = (); + + fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + +impl CanDeriveDefault for Opaque { + type Extra = (); + + fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + +impl<'a> CanDeriveCopy<'a> for Opaque { + type Extra = (); + + fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } + + fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { + self.can_derive_copy(ctx, ()) + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs index d703e53dbb..c4f2ccae53 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,23 +1,23 @@ -//! The ir module defines bindgen's intermediate representation. -//! -//! Parsing C/C++ generates the IR, while code generation outputs Rust code from -//! the IR. - -pub mod annotations; -pub mod comp; -pub mod context; -pub mod derive; -pub mod dot; -pub mod enum_ty; -pub mod function; -pub mod int; -pub mod item; -pub mod item_kind; -pub mod layout; -pub mod module; -pub mod named; -pub mod template; -pub mod traversal; -pub mod ty; -pub mod var; -pub mod objc; +//! The ir module defines bindgen's intermediate representation. +//! +//! Parsing C/C++ generates the IR, while code generation outputs Rust code from +//! the IR. + +pub mod annotations; +pub mod comp; +pub mod context; +pub mod derive; +pub mod dot; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod named; +pub mod template; +pub mod traversal; +pub mod ty; +pub mod var; +pub mod objc; diff --git a/src/ir/module.rs b/src/ir/module.rs index ee3912c5f1..292cbb6b40 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,91 +1,91 @@ -//! Intermediate representation for modules (AKA C++ namespaces). - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use clang; -use parse::{ClangSubItemParser, ParseError, ParseResult}; -use parse_one; -use std::io; - -/// Whether this module is inline or not. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ModuleKind { - /// This module is not inline. - Normal, - /// This module is inline, as in `inline namespace foo {}`. - Inline, -} - -/// A module, as in, a C++ namespace. -#[derive(Clone, Debug)] -pub struct Module { - /// The name of the module, or none if it's anonymous. - name: Option, - /// The kind of module this is. - kind: ModuleKind, - /// The children of this module, just here for convenience. - children_ids: Vec, -} - -impl Module { - /// Construct a new `Module`. - pub fn new(name: Option, kind: ModuleKind) -> Self { - Module { - name: name, - kind: kind, - children_ids: vec![], - } - } - - /// Get this module's name. - pub fn name(&self) -> Option<&str> { - self.name.as_ref().map(|n| &**n) - } - - /// Get a mutable reference to this module's children. - pub fn children_mut(&mut self) -> &mut Vec { - &mut self.children_ids - } - - /// Get this module's children. - pub fn children(&self) -> &[ItemId] { - &self.children_ids - } - - /// Whether this namespace is inline. - pub fn is_inline(&self) -> bool { - self.kind == ModuleKind::Inline - } -} - -impl DotAttributes for Module { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - writeln!(out, "ModuleKind{:?}", self.kind) - } -} - -impl ClangSubItemParser for Module { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - match cursor.kind() { - CXCursor_Namespace => { - let module_id = ctx.module(cursor); - ctx.with_module(module_id, |ctx| { - cursor.visit(|cursor| { - parse_one(ctx, cursor, Some(module_id)) - }) - }); - - Ok(ParseResult::AlreadyResolved(module_id)) - } - _ => Err(ParseError::Continue), - } - } -} +//! Intermediate representation for modules (AKA C++ namespaces). + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; +use std::io; + +/// Whether this module is inline or not. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ModuleKind { + /// This module is not inline. + Normal, + /// This module is inline, as in `inline namespace foo {}`. + Inline, +} + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option, + /// The kind of module this is. + kind: ModuleKind, + /// The children of this module, just here for convenience. + children_ids: Vec, +} + +impl Module { + /// Construct a new `Module`. + pub fn new(name: Option, kind: ModuleKind) -> Self { + Module { + name: name, + kind: kind, + children_ids: vec![], + } + } + + /// Get this module's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get a mutable reference to this module's children. + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children_ids + } + + /// Get this module's children. + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } + + /// Whether this namespace is inline. + pub fn is_inline(&self) -> bool { + self.kind == ModuleKind::Inline + } +} + +impl DotAttributes for Module { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + writeln!(out, "ModuleKind{:?}", self.kind) + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx| { + cursor.visit(|cursor| { + parse_one(ctx, cursor, Some(module_id)) + }) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue), + } + } +} diff --git a/src/ir/objc.rs b/src/ir/objc.rs index 3a88eef8ab..7b6227431f 100644 --- a/src/ir/objc.rs +++ b/src/ir/objc.rs @@ -1,254 +1,254 @@ -//! Objective C types - -use super::context::{BindgenContext, ItemId}; -use super::function::FunctionSig; -use super::traversal::{Trace, Tracer}; -use super::ty::TypeKind; -use clang; -use clang_sys::CXChildVisit_Continue; -use clang_sys::CXCursor_ObjCCategoryDecl; -use clang_sys::CXCursor_ObjCClassMethodDecl; -use clang_sys::CXCursor_ObjCClassRef; -use clang_sys::CXCursor_ObjCInstanceMethodDecl; -use clang_sys::CXCursor_ObjCProtocolDecl; -use clang_sys::CXCursor_ObjCProtocolRef; - -/// Objective C interface as used in TypeKind -/// -/// Also protocols and categories are parsed as this type -#[derive(Debug)] -pub struct ObjCInterface { - /// The name - /// like, NSObject - name: String, - - category: Option, - - is_protocol: bool, - - conforms_to: Vec, - - /// List of the methods defined in this interfae - methods: Vec, - - class_methods: Vec, -} - -/// The objective c methods -#[derive(Debug)] -pub struct ObjCMethod { - /// The original method selector name - /// like, dataWithBytes:length: - name: String, - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - rust_name: String, - - signature: FunctionSig, - - /// Is class method? - is_class_method: bool, -} - -impl ObjCInterface { - fn new(name: &str) -> ObjCInterface { - ObjCInterface { - name: name.to_owned(), - category: None, - is_protocol: false, - conforms_to: Vec::new(), - methods: Vec::new(), - class_methods: Vec::new(), - } - } - - /// The name - /// like, NSObject - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Formats the name for rust - /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods - /// and protocols are like protocol_NSObject - pub fn rust_name(&self) -> String { - if let Some(ref cat) = self.category { - format!("{}_{}", self.name(), cat) - } else { - if self.is_protocol { - format!("protocol_{}", self.name()) - } else { - self.name().to_owned() - } - } - } - - /// List of the methods defined in this interface - pub fn methods(&self) -> &Vec { - &self.methods - } - - /// List of the class methods defined in this interface - pub fn class_methods(&self) -> &Vec { - &self.class_methods - } - - /// Parses the Objective C interface from the cursor - pub fn from_ty(cursor: &clang::Cursor, - ctx: &mut BindgenContext) - -> Option { - let name = cursor.spelling(); - let mut interface = Self::new(&name); - - if cursor.kind() == CXCursor_ObjCProtocolDecl { - interface.is_protocol = true; - } - - cursor.visit(|c| { - match c.kind() { - CXCursor_ObjCClassRef => { - if cursor.kind() == CXCursor_ObjCCategoryDecl { - // We are actually a category extension, and we found the reference - // to the original interface, so name this interface approriately - interface.name = c.spelling(); - interface.category = Some(cursor.spelling()); - } - } - CXCursor_ObjCProtocolRef => { - // Gather protocols this interface conforms to - let needle = format!("protocol_{}", c.spelling()); - let items_map = ctx.items(); - debug!("Interface {} conforms to {}, find the item", interface.name, needle); - - for (id, item) in items_map - { - if let Some(ty) = item.as_type() { - match *ty.kind() { - TypeKind::ObjCInterface(ref protocol) => { - if protocol.is_protocol - { - debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); - if Some(needle.as_ref()) == ty.name() - { - debug!("Found conforming protocol {:?}", item); - interface.conforms_to.push(*id); - break; - } - } - } - _ => {} - } - } - } - - } - CXCursor_ObjCInstanceMethodDecl | - CXCursor_ObjCClassMethodDecl => { - let name = c.spelling(); - let signature = - FunctionSig::from_ty(&c.cur_type(), &c, ctx) - .expect("Invalid function sig"); - let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; - let method = ObjCMethod::new(&name, signature, is_class_method); - interface.add_method(method); - } - _ => {} - } - CXChildVisit_Continue - }); - Some(interface) - } - - fn add_method(&mut self, method: ObjCMethod) { - if method.is_class_method { - self.class_methods.push(method); - } else { - self.methods.push(method); - } - } -} - -impl ObjCMethod { - fn new(name: &str, - signature: FunctionSig, - is_class_method: bool) - -> ObjCMethod { - let split_name: Vec<&str> = name.split(':').collect(); - - let rust_name = split_name.join("_"); - - ObjCMethod { - name: name.to_owned(), - rust_name: rust_name.to_owned(), - signature: signature, - is_class_method: is_class_method, - } - } - - /// The original method selector name - /// like, dataWithBytes:length: - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - pub fn rust_name(&self) -> &str { - self.rust_name.as_ref() - } - - /// Returns the methods signature as FunctionSig - pub fn signature(&self) -> &FunctionSig { - &self.signature - } - - /// Is this a class method? - pub fn is_class_method(&self) -> bool { - self.is_class_method - } - - /// Formats the method call - pub fn format_method_call(&self, args: &[String]) -> String { - let split_name: Vec<&str> = - self.name.split(':').filter(|p| !p.is_empty()).collect(); - - // No arguments - if args.len() == 0 && split_name.len() == 1 { - return split_name[0].to_string(); - } - - // Check right amount of arguments - if args.len() != split_name.len() { - panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", - args, - split_name); - } - - split_name.iter() - .zip(args.iter()) - .map(|parts| format!("{}:{} ", parts.0, parts.1)) - .collect::>() - .join("") - } -} - -impl Trace for ObjCInterface { - type Extra = (); - - fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) - where T: Tracer, - { - for method in &self.methods { - method.signature.trace(context, tracer, &()); - } - - for class_method in &self.class_methods { - class_method.signature.trace(context, tracer, &()); - } - - for protocol in &self.conforms_to { - tracer.visit(*protocol); - } - } -} +//! Objective C types + +use super::context::{BindgenContext, ItemId}; +use super::function::FunctionSig; +use super::traversal::{Trace, Tracer}; +use super::ty::TypeKind; +use clang; +use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCCategoryDecl; +use clang_sys::CXCursor_ObjCClassMethodDecl; +use clang_sys::CXCursor_ObjCClassRef; +use clang_sys::CXCursor_ObjCInstanceMethodDecl; +use clang_sys::CXCursor_ObjCProtocolDecl; +use clang_sys::CXCursor_ObjCProtocolRef; + +/// Objective C interface as used in TypeKind +/// +/// Also protocols and categories are parsed as this type +#[derive(Debug)] +pub struct ObjCInterface { + /// The name + /// like, NSObject + name: String, + + category: Option, + + is_protocol: bool, + + conforms_to: Vec, + + /// List of the methods defined in this interfae + methods: Vec, + + class_methods: Vec, +} + +/// The objective c methods +#[derive(Debug)] +pub struct ObjCMethod { + /// The original method selector name + /// like, dataWithBytes:length: + name: String, + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + rust_name: String, + + signature: FunctionSig, + + /// Is class method? + is_class_method: bool, +} + +impl ObjCInterface { + fn new(name: &str) -> ObjCInterface { + ObjCInterface { + name: name.to_owned(), + category: None, + is_protocol: false, + conforms_to: Vec::new(), + methods: Vec::new(), + class_methods: Vec::new(), + } + } + + /// The name + /// like, NSObject + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + /// and protocols are like protocol_NSObject + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + if self.is_protocol { + format!("protocol_{}", self.name()) + } else { + self.name().to_owned() + } + } + } + + /// List of the methods defined in this interface + pub fn methods(&self) -> &Vec { + &self.methods + } + + /// List of the class methods defined in this interface + pub fn class_methods(&self) -> &Vec { + &self.class_methods + } + + /// Parses the Objective C interface from the cursor + pub fn from_ty(cursor: &clang::Cursor, + ctx: &mut BindgenContext) + -> Option { + let name = cursor.spelling(); + let mut interface = Self::new(&name); + + if cursor.kind() == CXCursor_ObjCProtocolDecl { + interface.is_protocol = true; + } + + cursor.visit(|c| { + match c.kind() { + CXCursor_ObjCClassRef => { + if cursor.kind() == CXCursor_ObjCCategoryDecl { + // We are actually a category extension, and we found the reference + // to the original interface, so name this interface approriately + interface.name = c.spelling(); + interface.category = Some(cursor.spelling()); + } + } + CXCursor_ObjCProtocolRef => { + // Gather protocols this interface conforms to + let needle = format!("protocol_{}", c.spelling()); + let items_map = ctx.items(); + debug!("Interface {} conforms to {}, find the item", interface.name, needle); + + for (id, item) in items_map + { + if let Some(ty) = item.as_type() { + match *ty.kind() { + TypeKind::ObjCInterface(ref protocol) => { + if protocol.is_protocol + { + debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); + if Some(needle.as_ref()) == ty.name() + { + debug!("Found conforming protocol {:?}", item); + interface.conforms_to.push(*id); + break; + } + } + } + _ => {} + } + } + } + + } + CXCursor_ObjCInstanceMethodDecl | + CXCursor_ObjCClassMethodDecl => { + let name = c.spelling(); + let signature = + FunctionSig::from_ty(&c.cur_type(), &c, ctx) + .expect("Invalid function sig"); + let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; + let method = ObjCMethod::new(&name, signature, is_class_method); + interface.add_method(method); + } + _ => {} + } + CXChildVisit_Continue + }); + Some(interface) + } + + fn add_method(&mut self, method: ObjCMethod) { + if method.is_class_method { + self.class_methods.push(method); + } else { + self.methods.push(method); + } + } +} + +impl ObjCMethod { + fn new(name: &str, + signature: FunctionSig, + is_class_method: bool) + -> ObjCMethod { + let split_name: Vec<&str> = name.split(':').collect(); + + let rust_name = split_name.join("_"); + + ObjCMethod { + name: name.to_owned(), + rust_name: rust_name.to_owned(), + signature: signature, + is_class_method: is_class_method, + } + } + + /// The original method selector name + /// like, dataWithBytes:length: + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + pub fn rust_name(&self) -> &str { + self.rust_name.as_ref() + } + + /// Returns the methods signature as FunctionSig + pub fn signature(&self) -> &FunctionSig { + &self.signature + } + + /// Is this a class method? + pub fn is_class_method(&self) -> bool { + self.is_class_method + } + + /// Formats the method call + pub fn format_method_call(&self, args: &[String]) -> String { + let split_name: Vec<&str> = + self.name.split(':').filter(|p| !p.is_empty()).collect(); + + // No arguments + if args.len() == 0 && split_name.len() == 1 { + return split_name[0].to_string(); + } + + // Check right amount of arguments + if args.len() != split_name.len() { + panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", + args, + split_name); + } + + split_name.iter() + .zip(args.iter()) + .map(|parts| format!("{}:{} ", parts.0, parts.1)) + .collect::>() + .join("") + } +} + +impl Trace for ObjCInterface { + type Extra = (); + + fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) + where T: Tracer, + { + for method in &self.methods { + method.signature.trace(context, tracer, &()); + } + + for class_method in &self.class_methods { + class_method.signature.trace(context, tracer, &()); + } + + for protocol in &self.conforms_to { + tracer.visit(*protocol); + } + } +} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index 95d2a45675..2ee75a9a6d 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -1,476 +1,476 @@ -//! Traversal of the graph of IR items and types. - -use super::context::{BindgenContext, ItemId}; -use super::item::ItemSet; -use std::collections::{BTreeMap, VecDeque}; - -/// An outgoing edge in the IR graph is a reference from some item to another -/// item: -/// -/// from --> to -/// -/// The `from` is left implicit: it is the concrete `Trace` implementor which -/// yielded this outgoing edge. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Edge { - to: ItemId, - kind: EdgeKind, -} - -impl Edge { - /// Construct a new edge whose referent is `to` and is of the given `kind`. - pub fn new(to: ItemId, kind: EdgeKind) -> Edge { - Edge { - to: to, - kind: kind, - } - } - - /// Get the item that this edge is pointing to. - pub fn to(&self) -> ItemId { - self.to - } - - /// Get the kind of edge that this is. - pub fn kind(&self) -> EdgeKind { - self.kind - } -} - -impl Into for Edge { - fn into(self) -> ItemId { - self.to - } -} - -/// The kind of edge reference. This is useful when we wish to only consider -/// certain kinds of edges for a particular traversal or analysis. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EdgeKind { - /// A generic, catch-all edge. - Generic, - - /// An edge from a template declaration, to the definition of a named type - /// parameter. For example, the edge from `Foo` to `T` in the following - /// snippet: - /// - /// ```C++ - /// template - /// class Foo { }; - /// ``` - TemplateParameterDefinition, - - /// An edge from a template instantiation to the template declaration that - /// is being instantiated. For example, the edge from `Foo` to - /// to `Foo`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// using Bar = Foo; - /// ``` - TemplateDeclaration, - - /// An edge from a template instantiation to its template argument. For - /// example, `Foo` to `Bar`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// class Bar { }; - /// - /// using FooBar = Foo; - /// ``` - TemplateArgument, - - /// An edge from a compound type to one of its base member types. For - /// example, the edge from `Bar` to `Foo`: - /// - /// ```C++ - /// class Foo { }; - /// - /// class Bar : public Foo { }; - /// ``` - BaseMember, - - /// An edge from a compound type to the types of one of its fields. For - /// example, the edge from `Foo` to `int`: - /// - /// ```C++ - /// class Foo { - /// int x; - /// }; - /// ``` - Field, - - /// An edge from an class or struct type to an inner type member. For - /// example, the edge from `Foo` to `Foo::Bar` here: - /// - /// ```C++ - /// class Foo { - /// struct Bar { }; - /// }; - /// ``` - InnerType, - - /// An edge from an class or struct type to an inner static variable. For - /// example, the edge from `Foo` to `Foo::BAR` here: - /// - /// ```C++ - /// class Foo { - /// static const char* BAR; - /// }; - /// ``` - InnerVar, - - /// An edge from a class or struct type to one of its method functions. For - /// example, the edge from `Foo` to `Foo::bar`: - /// - /// ```C++ - /// class Foo { - /// bool bar(int x, int y); - /// }; - /// ``` - Method, - - /// An edge from a class or struct type to one of its constructor - /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: - /// - /// ```C++ - /// class Foo { - /// int my_x; - /// int my_y; - /// - /// public: - /// Foo(int x, int y); - /// }; - /// ``` - Constructor, - - /// An edge from a function declaration to its return type. For example, the - /// edge from `foo` to `int`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionReturn, - - /// An edge from a function declaration to one of its parameter types. For - /// example, the edge from `foo` to `char*`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionParameter, - - /// An edge from a static variable to its type. For example, the edge from - /// `FOO` to `const char*`: - /// - /// ```C++ - /// static const char* FOO; - /// ``` - VarType, - - /// An edge from a non-templated alias or typedef to the referenced type. - TypeReference, -} - -/// A predicate to allow visiting only sub-sets of the whole IR graph by -/// excluding certain edges from being followed by the traversal. -pub trait TraversalPredicate { - /// Should the traversal follow this edge, and visit everything that is - /// reachable through it? - fn should_follow(&self, edge: Edge) -> bool; -} - -impl TraversalPredicate for fn(Edge) -> bool { - fn should_follow(&self, edge: Edge) -> bool { - (*self)(edge) - } -} - -/// A `TraversalPredicate` implementation that follows all edges, and therefore -/// traversals using this predicate will see the whole IR graph reachable from -/// the traversal's roots. -pub fn all_edges(_: Edge) -> bool { - true -} - -/// A `TraversalPredicate` implementation that never follows any edges, and -/// therefore traversals using this predicate will only visit the traversal's -/// roots. -pub fn no_edges(_: Edge) -> bool { - false -} - -/// The storage for the set of items that have been seen (although their -/// outgoing edges might not have been fully traversed yet) in an active -/// traversal. -pub trait TraversalStorage<'ctx, 'gen> { - /// Construct a new instance of this TraversalStorage, for a new traversal. - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; - - /// Add the given item to the storage. If the item has never been seen - /// before, return `true`. Otherwise, return `false`. - /// - /// The `from` item is the item from which we discovered this item, or is - /// `None` if this item is a root. - fn add(&mut self, from: Option, item: ItemId) -> bool; -} - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { - fn new(_: &'ctx BindgenContext<'gen>) -> Self { - ItemSet::new() - } - - fn add(&mut self, _: Option, item: ItemId) -> bool { - self.insert(item) - } -} - -/// A `TraversalStorage` implementation that keeps track of how we first reached -/// each item. This is useful for providing debug assertions with meaningful -/// diagnostic messages about dangling items. -#[derive(Debug)] -pub struct Paths<'ctx, 'gen>(BTreeMap, - &'ctx BindgenContext<'gen>) - where 'gen: 'ctx; - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> - where 'gen: 'ctx, -{ - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { - Paths(BTreeMap::new(), ctx) - } - - fn add(&mut self, from: Option, item: ItemId) -> bool { - let newly_discovered = - self.0.insert(item, from.unwrap_or(item)).is_none(); - - if self.1.resolve_item_fallible(item).is_none() { - let mut path = vec![]; - let mut current = item; - loop { - let predecessor = *self.0 - .get(¤t) - .expect("We know we found this item id, so it must have a \ - predecessor"); - if predecessor == current { - break; - } - path.push(predecessor); - current = predecessor; - } - path.reverse(); - panic!("Found reference to dangling id = {:?}\nvia path = {:?}", - item, - path); - } - - newly_discovered - } -} - -/// The queue of seen-but-not-yet-traversed items. -/// -/// Using a FIFO queue with a traversal will yield a breadth-first traversal, -/// while using a LIFO queue will result in a depth-first traversal of the IR -/// graph. -pub trait TraversalQueue: Default { - /// Add a newly discovered item to the queue. - fn push(&mut self, item: ItemId); - - /// Pop the next item to traverse, if any. - fn next(&mut self) -> Option; -} - -impl TraversalQueue for Vec { - fn push(&mut self, item: ItemId) { - self.push(item); - } - - fn next(&mut self) -> Option { - self.pop() - } -} - -impl TraversalQueue for VecDeque { - fn push(&mut self, item: ItemId) { - self.push_back(item); - } - - fn next(&mut self) -> Option { - self.pop_front() - } -} - -/// Something that can receive edges from a `Trace` implementation. -pub trait Tracer { - /// Note an edge between items. Called from within a `Trace` implementation. - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); - - /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. - fn visit(&mut self, item: ItemId) { - self.visit_kind(item, EdgeKind::Generic); - } -} - -impl Tracer for F - where F: FnMut(ItemId, EdgeKind), -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - (*self)(item, kind) - } -} - -/// Trace all of the outgoing edges to other items. Implementations should call -/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` -/// for each of their outgoing edges. -pub trait Trace { - /// If a particular type needs extra information beyond what it has in - /// `self` and `context` to find its referenced items, its implementation - /// can define this associated type, forcing callers to pass the needed - /// information through. - type Extra; - - /// Trace all of this item's outgoing edges to other items. - fn trace(&self, - context: &BindgenContext, - tracer: &mut T, - extra: &Self::Extra) - where T: Tracer; -} - -/// An graph traversal of the transitive closure of references between items. -/// -/// See `BindgenContext::whitelisted_items` for more information. -pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - ctx: &'ctx BindgenContext<'gen>, - - /// The set of items we have seen thus far in this traversal. - seen: Storage, - - /// The set of items that we have seen, but have yet to traverse. - queue: Queue, - - /// The predicate that determins which edges this traversal will follow. - predicate: Predicate, - - /// The item we are currently traversing. - currently_traversing: Option, -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, - 'gen, - Storage, - Queue, - Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - /// Begin a new traversal, starting from the given roots. - pub fn new(ctx: &'ctx BindgenContext<'gen>, - roots: R, - predicate: Predicate) - -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where R: IntoIterator, - { - let mut seen = Storage::new(ctx); - let mut queue = Queue::default(); - - for id in roots { - seen.add(None, id); - queue.push(id); - } - - ItemTraversal { - ctx: ctx, - seen: seen, - queue: queue, - predicate: predicate, - currently_traversing: None, - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - let edge = Edge::new(item, kind); - if !self.predicate.should_follow(edge) { - return; - } - - let is_newly_discovered = self.seen - .add(self.currently_traversing, item); - if is_newly_discovered { - self.queue.push(item) - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - type Item = ItemId; - - fn next(&mut self) -> Option { - let id = match self.queue.next() { - None => return None, - Some(id) => id, - }; - - let newly_discovered = self.seen.add(None, id); - debug_assert!(!newly_discovered, - "should have already seen anything we get out of our queue"); - debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), - "should only get IDs of actual items in our context during traversal"); - - self.currently_traversing = Some(id); - id.trace(self.ctx, self, &()); - self.currently_traversing = None; - - Some(id) - } -} - -/// An iterator to find any dangling items. -/// -/// See `BindgenContext::assert_no_dangling_item_traversal` for more -/// information. -pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = - ItemTraversal<'ctx, - 'gen, - Paths<'ctx, 'gen>, - VecDeque, - fn(Edge) -> bool>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[allow(dead_code)] - fn traversal_predicate_is_object_safe() { - // This should compile only if TraversalPredicate is object safe. - fn takes_by_trait_object(_: &TraversalPredicate) {} - } -} +//! Traversal of the graph of IR items and types. + +use super::context::{BindgenContext, ItemId}; +use super::item::ItemSet; +use std::collections::{BTreeMap, VecDeque}; + +/// An outgoing edge in the IR graph is a reference from some item to another +/// item: +/// +/// from --> to +/// +/// The `from` is left implicit: it is the concrete `Trace` implementor which +/// yielded this outgoing edge. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Edge { + to: ItemId, + kind: EdgeKind, +} + +impl Edge { + /// Construct a new edge whose referent is `to` and is of the given `kind`. + pub fn new(to: ItemId, kind: EdgeKind) -> Edge { + Edge { + to: to, + kind: kind, + } + } + + /// Get the item that this edge is pointing to. + pub fn to(&self) -> ItemId { + self.to + } + + /// Get the kind of edge that this is. + pub fn kind(&self) -> EdgeKind { + self.kind + } +} + +impl Into for Edge { + fn into(self) -> ItemId { + self.to + } +} + +/// The kind of edge reference. This is useful when we wish to only consider +/// certain kinds of edges for a particular traversal or analysis. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EdgeKind { + /// A generic, catch-all edge. + Generic, + + /// An edge from a template declaration, to the definition of a named type + /// parameter. For example, the edge from `Foo` to `T` in the following + /// snippet: + /// + /// ```C++ + /// template + /// class Foo { }; + /// ``` + TemplateParameterDefinition, + + /// An edge from a template instantiation to the template declaration that + /// is being instantiated. For example, the edge from `Foo` to + /// to `Foo`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// using Bar = Foo; + /// ``` + TemplateDeclaration, + + /// An edge from a template instantiation to its template argument. For + /// example, `Foo` to `Bar`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// class Bar { }; + /// + /// using FooBar = Foo; + /// ``` + TemplateArgument, + + /// An edge from a compound type to one of its base member types. For + /// example, the edge from `Bar` to `Foo`: + /// + /// ```C++ + /// class Foo { }; + /// + /// class Bar : public Foo { }; + /// ``` + BaseMember, + + /// An edge from a compound type to the types of one of its fields. For + /// example, the edge from `Foo` to `int`: + /// + /// ```C++ + /// class Foo { + /// int x; + /// }; + /// ``` + Field, + + /// An edge from an class or struct type to an inner type member. For + /// example, the edge from `Foo` to `Foo::Bar` here: + /// + /// ```C++ + /// class Foo { + /// struct Bar { }; + /// }; + /// ``` + InnerType, + + /// An edge from an class or struct type to an inner static variable. For + /// example, the edge from `Foo` to `Foo::BAR` here: + /// + /// ```C++ + /// class Foo { + /// static const char* BAR; + /// }; + /// ``` + InnerVar, + + /// An edge from a class or struct type to one of its method functions. For + /// example, the edge from `Foo` to `Foo::bar`: + /// + /// ```C++ + /// class Foo { + /// bool bar(int x, int y); + /// }; + /// ``` + Method, + + /// An edge from a class or struct type to one of its constructor + /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: + /// + /// ```C++ + /// class Foo { + /// int my_x; + /// int my_y; + /// + /// public: + /// Foo(int x, int y); + /// }; + /// ``` + Constructor, + + /// An edge from a function declaration to its return type. For example, the + /// edge from `foo` to `int`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionReturn, + + /// An edge from a function declaration to one of its parameter types. For + /// example, the edge from `foo` to `char*`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionParameter, + + /// An edge from a static variable to its type. For example, the edge from + /// `FOO` to `const char*`: + /// + /// ```C++ + /// static const char* FOO; + /// ``` + VarType, + + /// An edge from a non-templated alias or typedef to the referenced type. + TypeReference, +} + +/// A predicate to allow visiting only sub-sets of the whole IR graph by +/// excluding certain edges from being followed by the traversal. +pub trait TraversalPredicate { + /// Should the traversal follow this edge, and visit everything that is + /// reachable through it? + fn should_follow(&self, edge: Edge) -> bool; +} + +impl TraversalPredicate for fn(Edge) -> bool { + fn should_follow(&self, edge: Edge) -> bool { + (*self)(edge) + } +} + +/// A `TraversalPredicate` implementation that follows all edges, and therefore +/// traversals using this predicate will see the whole IR graph reachable from +/// the traversal's roots. +pub fn all_edges(_: Edge) -> bool { + true +} + +/// A `TraversalPredicate` implementation that never follows any edges, and +/// therefore traversals using this predicate will only visit the traversal's +/// roots. +pub fn no_edges(_: Edge) -> bool { + false +} + +/// The storage for the set of items that have been seen (although their +/// outgoing edges might not have been fully traversed yet) in an active +/// traversal. +pub trait TraversalStorage<'ctx, 'gen> { + /// Construct a new instance of this TraversalStorage, for a new traversal. + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; + + /// Add the given item to the storage. If the item has never been seen + /// before, return `true`. Otherwise, return `false`. + /// + /// The `from` item is the item from which we discovered this item, or is + /// `None` if this item is a root. + fn add(&mut self, from: Option, item: ItemId) -> bool; +} + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { + fn new(_: &'ctx BindgenContext<'gen>) -> Self { + ItemSet::new() + } + + fn add(&mut self, _: Option, item: ItemId) -> bool { + self.insert(item) + } +} + +/// A `TraversalStorage` implementation that keeps track of how we first reached +/// each item. This is useful for providing debug assertions with meaningful +/// diagnostic messages about dangling items. +#[derive(Debug)] +pub struct Paths<'ctx, 'gen>(BTreeMap, + &'ctx BindgenContext<'gen>) + where 'gen: 'ctx; + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> + where 'gen: 'ctx, +{ + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { + Paths(BTreeMap::new(), ctx) + } + + fn add(&mut self, from: Option, item: ItemId) -> bool { + let newly_discovered = + self.0.insert(item, from.unwrap_or(item)).is_none(); + + if self.1.resolve_item_fallible(item).is_none() { + let mut path = vec![]; + let mut current = item; + loop { + let predecessor = *self.0 + .get(¤t) + .expect("We know we found this item id, so it must have a \ + predecessor"); + if predecessor == current { + break; + } + path.push(predecessor); + current = predecessor; + } + path.reverse(); + panic!("Found reference to dangling id = {:?}\nvia path = {:?}", + item, + path); + } + + newly_discovered + } +} + +/// The queue of seen-but-not-yet-traversed items. +/// +/// Using a FIFO queue with a traversal will yield a breadth-first traversal, +/// while using a LIFO queue will result in a depth-first traversal of the IR +/// graph. +pub trait TraversalQueue: Default { + /// Add a newly discovered item to the queue. + fn push(&mut self, item: ItemId); + + /// Pop the next item to traverse, if any. + fn next(&mut self) -> Option; +} + +impl TraversalQueue for Vec { + fn push(&mut self, item: ItemId) { + self.push(item); + } + + fn next(&mut self) -> Option { + self.pop() + } +} + +impl TraversalQueue for VecDeque { + fn push(&mut self, item: ItemId) { + self.push_back(item); + } + + fn next(&mut self) -> Option { + self.pop_front() + } +} + +/// Something that can receive edges from a `Trace` implementation. +pub trait Tracer { + /// Note an edge between items. Called from within a `Trace` implementation. + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); + + /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. + fn visit(&mut self, item: ItemId) { + self.visit_kind(item, EdgeKind::Generic); + } +} + +impl Tracer for F + where F: FnMut(ItemId, EdgeKind), +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + (*self)(item, kind) + } +} + +/// Trace all of the outgoing edges to other items. Implementations should call +/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` +/// for each of their outgoing edges. +pub trait Trace { + /// If a particular type needs extra information beyond what it has in + /// `self` and `context` to find its referenced items, its implementation + /// can define this associated type, forcing callers to pass the needed + /// information through. + type Extra; + + /// Trace all of this item's outgoing edges to other items. + fn trace(&self, + context: &BindgenContext, + tracer: &mut T, + extra: &Self::Extra) + where T: Tracer; +} + +/// An graph traversal of the transitive closure of references between items. +/// +/// See `BindgenContext::whitelisted_items` for more information. +pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + ctx: &'ctx BindgenContext<'gen>, + + /// The set of items we have seen thus far in this traversal. + seen: Storage, + + /// The set of items that we have seen, but have yet to traverse. + queue: Queue, + + /// The predicate that determins which edges this traversal will follow. + predicate: Predicate, + + /// The item we are currently traversing. + currently_traversing: Option, +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, + 'gen, + Storage, + Queue, + Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + /// Begin a new traversal, starting from the given roots. + pub fn new(ctx: &'ctx BindgenContext<'gen>, + roots: R, + predicate: Predicate) + -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where R: IntoIterator, + { + let mut seen = Storage::new(ctx); + let mut queue = Queue::default(); + + for id in roots { + seen.add(None, id); + queue.push(id); + } + + ItemTraversal { + ctx: ctx, + seen: seen, + queue: queue, + predicate: predicate, + currently_traversing: None, + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + let edge = Edge::new(item, kind); + if !self.predicate.should_follow(edge) { + return; + } + + let is_newly_discovered = self.seen + .add(self.currently_traversing, item); + if is_newly_discovered { + self.queue.push(item) + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + type Item = ItemId; + + fn next(&mut self) -> Option { + let id = match self.queue.next() { + None => return None, + Some(id) => id, + }; + + let newly_discovered = self.seen.add(None, id); + debug_assert!(!newly_discovered, + "should have already seen anything we get out of our queue"); + debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), + "should only get IDs of actual items in our context during traversal"); + + self.currently_traversing = Some(id); + id.trace(self.ctx, self, &()); + self.currently_traversing = None; + + Some(id) + } +} + +/// An iterator to find any dangling items. +/// +/// See `BindgenContext::assert_no_dangling_item_traversal` for more +/// information. +pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = + ItemTraversal<'ctx, + 'gen, + Paths<'ctx, 'gen>, + VecDeque, + fn(Edge) -> bool>; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(dead_code)] + fn traversal_predicate_is_object_safe() { + // This should compile only if TraversalPredicate is object safe. + fn takes_by_trait_object(_: &TraversalPredicate) {} + } +} diff --git a/src/ir/var.rs b/src/ir/var.rs index 656a1a6dfd..ba9bfe0ede 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -1,342 +1,342 @@ -//! Intermediate representation of variables. - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use super::function::cursor_mangling; -use super::int::IntKind; -use super::item::Item; -use super::ty::{FloatKind, TypeKind}; -use cexpr; -use clang; -use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; -use std::io; -use std::num::Wrapping; - -/// The type for a constant variable. -#[derive(Debug)] -pub enum VarType { - /// A boolean. - Bool(bool), - /// An integer. - Int(i64), - /// A floating point number. - Float(f64), - /// A character. - Char(u8), - /// A string, not necessarily well-formed utf-8. - String(Vec), -} - -/// A `Var` is our intermediate representation of a variable. -#[derive(Debug)] -pub struct Var { - /// The name of the variable. - name: String, - /// The mangled name of the variable. - mangled_name: Option, - /// The type of the variable. - ty: ItemId, - /// The value of the variable, that needs to be suitable for `ty`. - val: Option, - /// Whether this variable is const. - is_const: bool, -} - -impl Var { - /// Construct a new `Var`. - pub fn new(name: String, - mangled: Option, - ty: ItemId, - val: Option, - is_const: bool) - -> Var { - assert!(!name.is_empty()); - Var { - name: name, - mangled_name: mangled, - ty: ty, - val: val, - is_const: is_const, - } - } - - /// Is this variable `const` qualified? - pub fn is_const(&self) -> bool { - self.is_const - } - - /// The value of this constant variable, if any. - pub fn val(&self) -> Option<&VarType> { - self.val.as_ref() - } - - /// Get this variable's type. - pub fn ty(&self) -> ItemId { - self.ty - } - - /// Get this variable's name. - pub fn name(&self) -> &str { - &self.name - } - - /// Get this variable's mangled name. - pub fn mangled_name(&self) -> Option<&str> { - self.mangled_name.as_ref().map(|n| &**n) - } -} - -impl DotAttributes for Var { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - if self.is_const { - try!(writeln!(out, "consttrue")); - } - - if let Some(ref mangled) = self.mangled_name { - try!(writeln!(out, - "mangled name{}", - mangled)); - } - - Ok(()) - } -} - -impl ClangSubItemParser for Var { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - use cexpr::expr::EvalResult; - use cexpr::literal::CChar; - match cursor.kind() { - CXCursor_MacroDefinition => { - - if let Some(visitor) = ctx.parse_callbacks() { - visitor.parsed_macro(&cursor.spelling()); - } - - let value = parse_macro(ctx, &cursor, ctx.translation_unit()); - - let (id, value) = match value { - Some(v) => v, - None => return Err(ParseError::Continue), - }; - - assert!(!id.is_empty(), "Empty macro name?"); - - let previously_defined = ctx.parsed_macro(&id); - - // NB: It's important to "note" the macro even if the result is - // not an integer, otherwise we might loose other kind of - // derived macros. - ctx.note_parsed_macro(id.clone(), value.clone()); - - if previously_defined { - let name = String::from_utf8(id).unwrap(); - warn!("Duplicated macro definition: {}", name); - return Err(ParseError::Continue); - } - - // NOTE: Unwrapping, here and above, is safe, because the - // identifier of a token comes straight from clang, and we - // enforce utf8 there, so we should have already panicked at - // this point. - let name = String::from_utf8(id).unwrap(); - let (type_kind, val) = match value { - EvalResult::Invalid => return Err(ParseError::Continue), - EvalResult::Float(f) => { - (TypeKind::Float(FloatKind::Double), VarType::Float(f)) - } - EvalResult::Char(c) => { - let c = match c { - CChar::Char(c) => { - assert_eq!(c.len_utf8(), 1); - c as u8 - } - CChar::Raw(c) => { - assert!(c <= ::std::u8::MAX as u64); - c as u8 - } - }; - - (TypeKind::Int(IntKind::U8), VarType::Char(c)) - } - EvalResult::Str(val) => { - let char_ty = - Item::builtin_type(TypeKind::Int(IntKind::U8), - true, - ctx); - (TypeKind::Pointer(char_ty), VarType::String(val)) - } - EvalResult::Int(Wrapping(value)) => { - let kind = ctx.parse_callbacks() - .and_then(|c| c.int_macro(&name, value)) - .unwrap_or_else(|| if value < 0 { - if value < i32::min_value() as i64 { - IntKind::LongLong - } else { - IntKind::Int - } - } else if value > u32::max_value() as i64 { - IntKind::ULongLong - } else { - IntKind::UInt - }); - - (TypeKind::Int(kind), VarType::Int(value)) - } - }; - - let ty = Item::builtin_type(type_kind, true, ctx); - - Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), - Some(cursor))) - } - CXCursor_VarDecl => { - let name = cursor.spelling(); - if name.is_empty() { - warn!("Empty constant name?"); - return Err(ParseError::Continue); - } - - let ty = cursor.cur_type(); - - // XXX this is redundant, remove! - let is_const = ty.is_const(); - - let ty = match Item::from_ty(&ty, cursor, None, ctx) { - Ok(ty) => ty, - Err(e) => { - assert_eq!(ty.kind(), - CXType_Auto, - "Couldn't resolve constant type, and it \ - wasn't an nondeductible auto type!"); - return Err(e); - } - }; - - // Note: Ty might not be totally resolved yet, see - // tests/headers/inner_const.hpp - // - // That's fine because in that case we know it's not a literal. - let canonical_ty = ctx.safe_resolve_type(ty) - .and_then(|t| t.safe_canonical_type(ctx)); - - let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); - let is_float = canonical_ty.map_or(false, |t| t.is_float()); - - // TODO: We could handle `char` more gracefully. - // TODO: Strings, though the lookup is a bit more hard (we need - // to look at the canonical type of the pointee too, and check - // is char, u8, or i8 I guess). - let value = if is_integer { - let kind = match *canonical_ty.unwrap().kind() { - TypeKind::Int(kind) => kind, - _ => unreachable!(), - }; - - let mut val = cursor.evaluate() - .and_then(|v| v.as_int()) - .map(|val| val as i64); - if val.is_none() || !kind.signedness_matches(val.unwrap()) { - let tu = ctx.translation_unit(); - val = get_integer_literal_from_cursor(&cursor, tu); - } - - val.map(|val| if kind == IntKind::Bool { - VarType::Bool(val != 0) - } else { - VarType::Int(val) - }) - } else if is_float { - cursor.evaluate() - .and_then(|v| v.as_double()) - .map(VarType::Float) - } else { - cursor.evaluate() - .and_then(|v| v.as_literal_string()) - .map(VarType::String) - }; - - let mangling = cursor_mangling(ctx, &cursor); - let var = Var::new(name, mangling, ty, value, is_const); - - Ok(ParseResult::New(var, Some(cursor))) - } - _ => { - /* TODO */ - Err(ParseError::Continue) - } - } - } -} - -/// Try and parse a macro using all the macros parsed until now. -fn parse_macro(ctx: &BindgenContext, - cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option<(Vec, cexpr::expr::EvalResult)> { - use cexpr::{expr, nom}; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - let parser = expr::IdentifierParser::new(ctx.parsed_macros()); - let result = parser.macro_definition(&cexpr_tokens); - - match result { - nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), - _ => None, - } -} - -fn parse_int_literal_tokens(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use cexpr::{expr, nom}; - use cexpr::expr::EvalResult; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - // TODO(emilio): We can try to parse other kinds of literals. - match expr::expr(&cexpr_tokens) { - nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), - _ => None, - } -} - -fn get_integer_literal_from_cursor(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use clang_sys::*; - let mut value = None; - cursor.visit(|c| { - match c.kind() { - CXCursor_IntegerLiteral | - CXCursor_UnaryOperator => { - value = parse_int_literal_tokens(&c, unit); - } - CXCursor_UnexposedExpr => { - value = get_integer_literal_from_cursor(&c, unit); - } - _ => (), - } - if value.is_some() { - CXChildVisit_Break - } else { - CXChildVisit_Continue - } - }); - value -} +//! Intermediate representation of variables. + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use super::function::cursor_mangling; +use super::int::IntKind; +use super::item::Item; +use super::ty::{FloatKind, TypeKind}; +use cexpr; +use clang; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; +use std::num::Wrapping; + +/// The type for a constant variable. +#[derive(Debug)] +pub enum VarType { + /// A boolean. + Bool(bool), + /// An integer. + Int(i64), + /// A floating point number. + Float(f64), + /// A character. + Char(u8), + /// A string, not necessarily well-formed utf-8. + String(Vec), +} + +/// A `Var` is our intermediate representation of a variable. +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option, + /// The type of the variable. + ty: ItemId, + /// The value of the variable, that needs to be suitable for `ty`. + val: Option, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + /// Construct a new `Var`. + pub fn new(name: String, + mangled: Option, + ty: ItemId, + val: Option, + is_const: bool) + -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + /// Is this variable `const` qualified? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// The value of this constant variable, if any. + pub fn val(&self) -> Option<&VarType> { + self.val.as_ref() + } + + /// Get this variable's type. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get this variable's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variable's mangled name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl DotAttributes for Var { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + if self.is_const { + try!(writeln!(out, "consttrue")); + } + + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, + "mangled name{}", + mangled)); + } + + Ok(()) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + use cexpr::expr::EvalResult; + use cexpr::literal::CChar; + match cursor.kind() { + CXCursor_MacroDefinition => { + + if let Some(visitor) = ctx.parse_callbacks() { + visitor.parsed_macro(&cursor.spelling()); + } + + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); + + let (id, value) = match value { + Some(v) => v, + None => return Err(ParseError::Continue), + }; + + assert!(!id.is_empty(), "Empty macro name?"); + + let previously_defined = ctx.parsed_macro(&id); + + // NB: It's important to "note" the macro even if the result is + // not an integer, otherwise we might loose other kind of + // derived macros. + ctx.note_parsed_macro(id.clone(), value.clone()); + + if previously_defined { + let name = String::from_utf8(id).unwrap(); + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + + // NOTE: Unwrapping, here and above, is safe, because the + // identifier of a token comes straight from clang, and we + // enforce utf8 there, so we should have already panicked at + // this point. + let name = String::from_utf8(id).unwrap(); + let (type_kind, val) = match value { + EvalResult::Invalid => return Err(ParseError::Continue), + EvalResult::Float(f) => { + (TypeKind::Float(FloatKind::Double), VarType::Float(f)) + } + EvalResult::Char(c) => { + let c = match c { + CChar::Char(c) => { + assert_eq!(c.len_utf8(), 1); + c as u8 + } + CChar::Raw(c) => { + assert!(c <= ::std::u8::MAX as u64); + c as u8 + } + }; + + (TypeKind::Int(IntKind::U8), VarType::Char(c)) + } + EvalResult::Str(val) => { + let char_ty = + Item::builtin_type(TypeKind::Int(IntKind::U8), + true, + ctx); + (TypeKind::Pointer(char_ty), VarType::String(val)) + } + EvalResult::Int(Wrapping(value)) => { + let kind = ctx.parse_callbacks() + .and_then(|c| c.int_macro(&name, value)) + .unwrap_or_else(|| if value < 0 { + if value < i32::min_value() as i64 { + IntKind::LongLong + } else { + IntKind::Int + } + } else if value > u32::max_value() as i64 { + IntKind::ULongLong + } else { + IntKind::UInt + }); + + (TypeKind::Int(kind), VarType::Int(value)) + } + }; + + let ty = Item::builtin_type(type_kind, true, ctx); + + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), + Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = match Item::from_ty(&ty, cursor, None, ctx) { + Ok(ty) => ty, + Err(e) => { + assert_eq!(ty.kind(), + CXType_Auto, + "Couldn't resolve constant type, and it \ + wasn't an nondeductible auto type!"); + return Err(e); + } + }; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + let canonical_ty = ctx.safe_resolve_type(ty) + .and_then(|t| t.safe_canonical_type(ctx)); + + let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); + let is_float = canonical_ty.map_or(false, |t| t.is_float()); + + // TODO: We could handle `char` more gracefully. + // TODO: Strings, though the lookup is a bit more hard (we need + // to look at the canonical type of the pointee too, and check + // is char, u8, or i8 I guess). + let value = if is_integer { + let kind = match *canonical_ty.unwrap().kind() { + TypeKind::Int(kind) => kind, + _ => unreachable!(), + }; + + let mut val = cursor.evaluate() + .and_then(|v| v.as_int()) + .map(|val| val as i64); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { + let tu = ctx.translation_unit(); + val = get_integer_literal_from_cursor(&cursor, tu); + } + + val.map(|val| if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + }) + } else if is_float { + cursor.evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float) + } else { + cursor.evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String) + }; + + let mangling = cursor_mangling(ctx, &cursor); + let var = Var::new(name, mangling, ty, value, is_const); + + Ok(ParseResult::New(var, Some(cursor))) + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +/// Try and parse a macro using all the macros parsed until now. +fn parse_macro(ctx: &BindgenContext, + cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<(Vec, cexpr::expr::EvalResult)> { + use cexpr::{expr, nom}; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); + let result = parser.macro_definition(&cexpr_tokens); + + match result { + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), + _ => None, + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use cexpr::{expr, nom}; + use cexpr::expr::EvalResult; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + // TODO(emilio): We can try to parse other kinds of literals. + match expr::expr(&cexpr_tokens) { + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), + _ => None, + } +} + +fn get_integer_literal_from_cursor(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use clang_sys::*; + let mut value = None; + cursor.visit(|c| { + match c.kind() { + CXCursor_IntegerLiteral | + CXCursor_UnaryOperator => { + value = parse_int_literal_tokens(&c, unit); + } + CXCursor_UnexposedExpr => { + value = get_integer_literal_from_cursor(&c, unit); + } + _ => (), + } + if value.is_some() { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + value +} From a996415522618b29b0ebaf65ff02a698584f177a Mon Sep 17 00:00:00 2001 From: Date: Mon, 17 Apr 2017 17:26:13 -0400 Subject: [PATCH 09/18] missed one --- .gitignore | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 91a6101e62..15430b5261 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ -# Cargo -target/ -*~ -bindgen-integration/Cargo.lock -tests/expectations/Cargo.lock -#*# -bindgen-integration/mybuild.rs -ir.dot -ir.png +# Cargo +target/ +*~ +bindgen-integration/Cargo.lock +tests/expectations/Cargo.lock +#*# +bindgen-integration/mybuild.rs +ir.dot +ir.png From 983ba0521593198af36c25b4048458ece054c77e Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 17:41:33 -0400 Subject: [PATCH 10/18] cleanup --- build.rs | 132 +++--- src/ir/annotations.rs | 376 ++++++++--------- src/ir/derive.rs | 176 ++++---- src/ir/dot.rs | 124 +++--- src/ir/enum_ty.rs | 380 ++++++++--------- src/ir/item_kind.rs | 294 ++++++------- src/ir/layout.rs | 268 ++++++------ src/ir/mod.rs | 46 +- src/ir/module.rs | 182 ++++---- src/ir/objc.rs | 508 +++++++++++----------- src/ir/traversal.rs | 952 +++++++++++++++++++++--------------------- src/ir/var.rs | 684 +++++++++++++++--------------- 12 files changed, 2061 insertions(+), 2061 deletions(-) diff --git a/build.rs b/build.rs index 86d80260df..bda91e28ac 100644 --- a/build.rs +++ b/build.rs @@ -1,66 +1,66 @@ -mod codegen { - extern crate quasi_codegen; - use std::env; - use std::path::{Path, PathBuf}; - - pub fn main() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let src = Path::new("src/codegen/mod.rs"); - let dst = Path::new(&out_dir).join("codegen.rs"); - - quasi_codegen::expand(&src, &dst).unwrap(); - println!("cargo:rerun-if-changed=src/codegen/mod.rs"); - println!("cargo:rerun-if-changed=src/codegen/error.rs"); - println!("cargo:rerun-if-changed=src/codegen/helpers.rs"); - println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs"); - } -} - -mod testgen { - use std::char; - use std::env; - use std::ffi::OsStr; - use std::fs::{self, File}; - use std::io::Write; - use std::path::{Path, PathBuf}; - - pub fn main() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); - - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let headers_dir = manifest_dir.join("tests").join("headers"); - - let headers = match fs::read_dir(headers_dir) { - Ok(dir) => dir, - // We may not have headers directory after packaging. - Err(..) => return, - }; - - let entries = - headers.map(|result| result.expect("Couldn't read header file")); - - println!("cargo:rerun-if-changed=tests/headers"); - - for entry in entries { - match entry.path().extension().and_then(OsStr::to_str) { - Some("h") | Some("hpp") => { - let func = entry.file_name().to_str().unwrap() - .replace(|c| !char::is_alphanumeric(c), "_") - .replace("__", "_") - .to_lowercase(); - writeln!(dst, "test_header!(header_{}, {:?});", - func, entry.path()).unwrap(); - } - _ => {} - } - } - - dst.flush().unwrap(); - } -} - -fn main() { - codegen::main(); - testgen::main(); -} +mod codegen { + extern crate quasi_codegen; + use std::env; + use std::path::{Path, PathBuf}; + + pub fn main() { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let src = Path::new("src/codegen/mod.rs"); + let dst = Path::new(&out_dir).join("codegen.rs"); + + quasi_codegen::expand(&src, &dst).unwrap(); + println!("cargo:rerun-if-changed=src/codegen/mod.rs"); + println!("cargo:rerun-if-changed=src/codegen/error.rs"); + println!("cargo:rerun-if-changed=src/codegen/helpers.rs"); + println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs"); + } +} + +mod testgen { + use std::char; + use std::env; + use std::ffi::OsStr; + use std::fs::{self, File}; + use std::io::Write; + use std::path::{Path, PathBuf}; + + pub fn main() { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); + + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let headers_dir = manifest_dir.join("tests").join("headers"); + + let headers = match fs::read_dir(headers_dir) { + Ok(dir) => dir, + // We may not have headers directory after packaging. + Err(..) => return, + }; + + let entries = + headers.map(|result| result.expect("Couldn't read header file")); + + println!("cargo:rerun-if-changed=tests/headers"); + + for entry in entries { + match entry.path().extension().and_then(OsStr::to_str) { + Some("h") | Some("hpp") => { + let func = entry.file_name().to_str().unwrap() + .replace(|c| !char::is_alphanumeric(c), "_") + .replace("__", "_") + .to_lowercase(); + writeln!(dst, "test_header!(header_{}, {:?});", + func, entry.path()).unwrap(); + } + _ => {} + } + } + + dst.flush().unwrap(); + } +} + +fn main() { + codegen::main(); + testgen::main(); +} diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs index 51c4ef6325..98be0540f2 100644 --- a/src/ir/annotations.rs +++ b/src/ir/annotations.rs @@ -1,188 +1,188 @@ -//! Types and functions related to bindgen annotation comments. -//! -//! Users can add annotations in doc comments to types that they would like to -//! replace other types with, mark as opaque, etc. This module deals with all of -//! that stuff. - -use clang; - -/// What kind of accessor should we provide for a field? -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum FieldAccessorKind { - /// No accessor. - None, - /// Plain accessor. - Regular, - /// Unsafe accessor. - Unsafe, - /// Immutable accessor. - Immutable, -} - -/// Annotations for a given item, or a field. -/// -/// You can see the kind of comments that are accepted in the Doxygen -/// documentation: -/// -/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html -#[derive(Clone, PartialEq, Debug)] -pub struct Annotations { - /// Whether this item is marked as opaque. Only applies to types. - opaque: bool, - /// Whether this item should be hidden from the output. Only applies to - /// types, or enum variants. - hide: bool, - /// Whether this type should be replaced by another. The name is a - /// namespace-aware path. - use_instead_of: Option>, - /// Manually disable deriving copy/clone on this type. Only applies to - /// struct or union types. - disallow_copy: bool, - /// Whether fields should be marked as private or not. You can set this on - /// structs (it will apply to all the fields), or individual fields. - private_fields: Option, - /// The kind of accessor this field will have. Also can be applied to - /// structs so all the fields inside share it by default. - accessor_kind: Option, - /// Whether this enum variant should be constified. - /// - /// This is controlled by the `constant` attribute, this way: - /// - /// ```cpp - /// enum Foo { - /// Bar = 0, /**<
*/ - /// Baz = 0, - /// }; - /// ``` - /// - /// In that case, bindgen will generate a constant for `Bar` instead of - /// `Baz`. - constify_enum_variant: bool, -} - -fn parse_accessor(s: &str) -> FieldAccessorKind { - match s { - "false" => FieldAccessorKind::None, - "unsafe" => FieldAccessorKind::Unsafe, - "immutable" => FieldAccessorKind::Immutable, - _ => FieldAccessorKind::Regular, - } -} - -impl Default for Annotations { - fn default() -> Self { - Annotations { - opaque: false, - hide: false, - use_instead_of: None, - disallow_copy: false, - private_fields: None, - accessor_kind: None, - constify_enum_variant: false, - } - } -} - -impl Annotations { - /// Construct new annotations for the given cursor and its bindgen comments - /// (if any). - pub fn new(cursor: &clang::Cursor) -> Option { - let mut anno = Annotations::default(); - let mut matched_one = false; - anno.parse(&cursor.comment(), &mut matched_one); - - if matched_one { Some(anno) } else { None } - } - - /// Should this type be hidden? - pub fn hide(&self) -> bool { - self.hide - } - - /// Should this type be opaque? - pub fn opaque(&self) -> bool { - self.opaque - } - - /// For a given type, indicates the type it should replace. - /// - /// For example, in the following code: - /// - /// ```cpp - /// - /// /**
*/ - /// struct Foo { int x; }; - /// - /// struct Bar { char foo; }; - /// ``` - /// - /// the generated code would look something like: - /// - /// ``` - /// /**
*/ - /// struct Bar { - /// x: ::std::os::raw::c_int, - /// }; - /// ``` - /// - /// That is, code for `Foo` is used to generate `Bar`. - pub fn use_instead_of(&self) -> Option<&[String]> { - self.use_instead_of.as_ref().map(|s| &**s) - } - - /// Should we avoid implementing the `Copy` trait? - pub fn disallow_copy(&self) -> bool { - self.disallow_copy - } - - /// Should the fields be private? - pub fn private_fields(&self) -> Option { - self.private_fields - } - - /// What kind of accessors should we provide for this type's fields? - pub fn accessor_kind(&self) -> Option { - self.accessor_kind - } - - fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { - use clang_sys::CXComment_HTMLStartTag; - if comment.kind() == CXComment_HTMLStartTag && - comment.get_tag_name() == "div" && - comment.get_tag_attrs() - .next() - .map_or(false, |attr| attr.name == "rustbindgen") { - *matched = true; - for attr in comment.get_tag_attrs() { - match attr.name.as_str() { - "opaque" => self.opaque = true, - "hide" => self.hide = true, - "nocopy" => self.disallow_copy = true, - "replaces" => { - self.use_instead_of = Some(attr.value - .split("::") - .map(Into::into) - .collect()) - } - "private" => { - self.private_fields = Some(attr.value != "false") - } - "accessor" => { - self.accessor_kind = Some(parse_accessor(&attr.value)) - } - "constant" => self.constify_enum_variant = true, - _ => {} - } - } - } - - for child in comment.get_children() { - self.parse(&child, matched); - } - } - - /// Returns whether we've parsed a "constant" attribute. - pub fn constify_enum_variant(&self) -> bool { - self.constify_enum_variant - } -} +//! Types and functions related to bindgen annotation comments. +//! +//! Users can add annotations in doc comments to types that they would like to +//! replace other types with, mark as opaque, etc. This module deals with all of +//! that stuff. + +use clang; + +/// What kind of accessor should we provide for a field? +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum FieldAccessorKind { + /// No accessor. + None, + /// Plain accessor. + Regular, + /// Unsafe accessor. + Unsafe, + /// Immutable accessor. + Immutable, +} + +/// Annotations for a given item, or a field. +/// +/// You can see the kind of comments that are accepted in the Doxygen +/// documentation: +/// +/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html +#[derive(Clone, PartialEq, Debug)] +pub struct Annotations { + /// Whether this item is marked as opaque. Only applies to types. + opaque: bool, + /// Whether this item should be hidden from the output. Only applies to + /// types, or enum variants. + hide: bool, + /// Whether this type should be replaced by another. The name is a + /// namespace-aware path. + use_instead_of: Option>, + /// Manually disable deriving copy/clone on this type. Only applies to + /// struct or union types. + disallow_copy: bool, + /// Whether fields should be marked as private or not. You can set this on + /// structs (it will apply to all the fields), or individual fields. + private_fields: Option, + /// The kind of accessor this field will have. Also can be applied to + /// structs so all the fields inside share it by default. + accessor_kind: Option, + /// Whether this enum variant should be constified. + /// + /// This is controlled by the `constant` attribute, this way: + /// + /// ```cpp + /// enum Foo { + /// Bar = 0, /**<
*/ + /// Baz = 0, + /// }; + /// ``` + /// + /// In that case, bindgen will generate a constant for `Bar` instead of + /// `Baz`. + constify_enum_variant: bool, +} + +fn parse_accessor(s: &str) -> FieldAccessorKind { + match s { + "false" => FieldAccessorKind::None, + "unsafe" => FieldAccessorKind::Unsafe, + "immutable" => FieldAccessorKind::Immutable, + _ => FieldAccessorKind::Regular, + } +} + +impl Default for Annotations { + fn default() -> Self { + Annotations { + opaque: false, + hide: false, + use_instead_of: None, + disallow_copy: false, + private_fields: None, + accessor_kind: None, + constify_enum_variant: false, + } + } +} + +impl Annotations { + /// Construct new annotations for the given cursor and its bindgen comments + /// (if any). + pub fn new(cursor: &clang::Cursor) -> Option { + let mut anno = Annotations::default(); + let mut matched_one = false; + anno.parse(&cursor.comment(), &mut matched_one); + + if matched_one { Some(anno) } else { None } + } + + /// Should this type be hidden? + pub fn hide(&self) -> bool { + self.hide + } + + /// Should this type be opaque? + pub fn opaque(&self) -> bool { + self.opaque + } + + /// For a given type, indicates the type it should replace. + /// + /// For example, in the following code: + /// + /// ```cpp + /// + /// /**
*/ + /// struct Foo { int x; }; + /// + /// struct Bar { char foo; }; + /// ``` + /// + /// the generated code would look something like: + /// + /// ``` + /// /**
*/ + /// struct Bar { + /// x: ::std::os::raw::c_int, + /// }; + /// ``` + /// + /// That is, code for `Foo` is used to generate `Bar`. + pub fn use_instead_of(&self) -> Option<&[String]> { + self.use_instead_of.as_ref().map(|s| &**s) + } + + /// Should we avoid implementing the `Copy` trait? + pub fn disallow_copy(&self) -> bool { + self.disallow_copy + } + + /// Should the fields be private? + pub fn private_fields(&self) -> Option { + self.private_fields + } + + /// What kind of accessors should we provide for this type's fields? + pub fn accessor_kind(&self) -> Option { + self.accessor_kind + } + + fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { + use clang_sys::CXComment_HTMLStartTag; + if comment.kind() == CXComment_HTMLStartTag && + comment.get_tag_name() == "div" && + comment.get_tag_attrs() + .next() + .map_or(false, |attr| attr.name == "rustbindgen") { + *matched = true; + for attr in comment.get_tag_attrs() { + match attr.name.as_str() { + "opaque" => self.opaque = true, + "hide" => self.hide = true, + "nocopy" => self.disallow_copy = true, + "replaces" => { + self.use_instead_of = Some(attr.value + .split("::") + .map(Into::into) + .collect()) + } + "private" => { + self.private_fields = Some(attr.value != "false") + } + "accessor" => { + self.accessor_kind = Some(parse_accessor(&attr.value)) + } + "constant" => self.constify_enum_variant = true, + _ => {} + } + } + } + + for child in comment.get_children() { + self.parse(&child, matched); + } + } + + /// Returns whether we've parsed a "constant" attribute. + pub fn constify_enum_variant(&self) -> bool { + self.constify_enum_variant + } +} diff --git a/src/ir/derive.rs b/src/ir/derive.rs index 6b4c766e11..0fc8debffa 100644 --- a/src/ir/derive.rs +++ b/src/ir/derive.rs @@ -1,88 +1,88 @@ -//! Traits for determining whether we can derive traits for a thing or not. - -use super::context::BindgenContext; - -/// A trait that encapsulates the logic for whether or not we can derive `Debug` -/// for a given thing. -/// -/// This should ideally be a no-op that just returns `true`, but instead needs -/// to be a recursive method that checks whether all the proper members can -/// derive debug or not, because of the limit rust has on 32 items as max in the -/// array. -pub trait CanDeriveDebug { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Debug`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Debug` can be derived for this thing, `false` - /// otherwise. - fn can_derive_debug(&self, - ctx: &BindgenContext, - extra: Self::Extra) - -> bool; -} - -/// A trait that encapsulates the logic for whether or not we can derive `Copy` -/// for a given thing. -pub trait CanDeriveCopy<'a> { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Copy`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Copy` can be derived for this thing, `false` - /// otherwise. - fn can_derive_copy(&'a self, - ctx: &'a BindgenContext, - extra: Self::Extra) - -> bool; - - /// For some reason, deriving copies of an array of a type that is not known - /// to be `Copy` is a compile error. e.g.: - /// - /// ```rust - /// #[derive(Copy, Clone)] - /// struct A { - /// member: T, - /// } - /// ``` - /// - /// is fine, while: - /// - /// ```rust,ignore - /// #[derive(Copy, Clone)] - /// struct A { - /// member: [T; 1], - /// } - /// ``` - /// - /// is an error. - /// - /// That's the whole point of the existence of `can_derive_copy_in_array`. - fn can_derive_copy_in_array(&'a self, - ctx: &'a BindgenContext, - extra: Self::Extra) - -> bool; -} - -/// A trait that encapsulates the logic for whether or not we can derive `Default` -/// for a given thing. -/// -/// This should ideally be a no-op that just returns `true`, but instead needs -/// to be a recursive method that checks whether all the proper members can -/// derive default or not, because of the limit rust has on 32 items as max in the -/// array. -pub trait CanDeriveDefault { - /// Implementations can define this type to get access to any extra - /// information required to determine whether they can derive `Default`. If - /// extra information is unneeded, then this should simply be the unit type. - type Extra; - - /// Return `true` if `Default` can be derived for this thing, `false` - /// otherwise. - fn can_derive_default(&self, - ctx: &BindgenContext, - extra: Self::Extra) - -> bool; -} +//! Traits for determining whether we can derive traits for a thing or not. + +use super::context::BindgenContext; + +/// A trait that encapsulates the logic for whether or not we can derive `Debug` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive debug or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDebug { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Debug`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Debug` can be derived for this thing, `false` + /// otherwise. + fn can_derive_debug(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +} + +/// A trait that encapsulates the logic for whether or not we can derive `Copy` +/// for a given thing. +pub trait CanDeriveCopy<'a> { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Copy`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Copy` can be derived for this thing, `false` + /// otherwise. + fn can_derive_copy(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; + + /// For some reason, deriving copies of an array of a type that is not known + /// to be `Copy` is a compile error. e.g.: + /// + /// ```rust + /// #[derive(Copy, Clone)] + /// struct A { + /// member: T, + /// } + /// ``` + /// + /// is fine, while: + /// + /// ```rust,ignore + /// #[derive(Copy, Clone)] + /// struct A { + /// member: [T; 1], + /// } + /// ``` + /// + /// is an error. + /// + /// That's the whole point of the existence of `can_derive_copy_in_array`. + fn can_derive_copy_in_array(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; +} + +/// A trait that encapsulates the logic for whether or not we can derive `Default` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive default or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDefault { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Default`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Default` can be derived for this thing, `false` + /// otherwise. + fn can_derive_default(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +} diff --git a/src/ir/dot.rs b/src/ir/dot.rs index 8a44c9025c..7472dd8e0f 100644 --- a/src/ir/dot.rs +++ b/src/ir/dot.rs @@ -1,62 +1,62 @@ -//! Generating Graphviz `dot` files from our IR. - -use super::context::{BindgenContext, ItemId}; -use super::traversal::Trace; -use std::fs::File; -use std::io::{self, Write}; -use std::path::Path; - -/// A trait for anything that can write attributes as `` rows to a dot -/// file. -pub trait DotAttributes { - /// Write this thing's attributes to the given output. Each attribute must - /// be its own `...`. - fn dot_attributes(&self, - ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write; -} - -/// Write a graphviz dot file containing our IR. -pub fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> - where P: AsRef, -{ - let file = try!(File::create(path)); - let mut dot_file = io::BufWriter::new(file); - try!(writeln!(&mut dot_file, "digraph {{")); - - let mut err: Option> = None; - - for (id, item) in ctx.items() { - try!(writeln!(&mut dot_file, - r#"{} [fontname="courier", label=<

"#, - id.as_usize())); - try!(item.dot_attributes(ctx, &mut dot_file)); - try!(writeln!(&mut dot_file, r#"
>];"#)); - - item.trace(ctx, - &mut |sub_id: ItemId, edge_kind| { - if err.is_some() { - return; - } - - match writeln!(&mut dot_file, - "{} -> {} [label={:?}];", - id.as_usize(), - sub_id.as_usize(), - edge_kind) { - Ok(_) => {} - Err(e) => err = Some(Err(e)), - } - }, - &()); - - if let Some(err) = err { - return err; - } - } - - try!(writeln!(&mut dot_file, "}}")); - Ok(()) -} +//! Generating Graphviz `dot` files from our IR. + +use super::context::{BindgenContext, ItemId}; +use super::traversal::Trace; +use std::fs::File; +use std::io::{self, Write}; +use std::path::Path; + +/// A trait for anything that can write attributes as `` rows to a dot +/// file. +pub trait DotAttributes { + /// Write this thing's attributes to the given output. Each attribute must + /// be its own `...`. + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write; +} + +/// Write a graphviz dot file containing our IR. +pub fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> + where P: AsRef, +{ + let file = try!(File::create(path)); + let mut dot_file = io::BufWriter::new(file); + try!(writeln!(&mut dot_file, "digraph {{")); + + let mut err: Option> = None; + + for (id, item) in ctx.items() { + try!(writeln!(&mut dot_file, + r#"{} [fontname="courier", label=<

"#, + id.as_usize())); + try!(item.dot_attributes(ctx, &mut dot_file)); + try!(writeln!(&mut dot_file, r#"
>];"#)); + + item.trace(ctx, + &mut |sub_id: ItemId, edge_kind| { + if err.is_some() { + return; + } + + match writeln!(&mut dot_file, + "{} -> {} [label={:?}];", + id.as_usize(), + sub_id.as_usize(), + edge_kind) { + Ok(_) => {} + Err(e) => err = Some(Err(e)), + } + }, + &()); + + if let Some(err) = err { + return err; + } + } + + try!(writeln!(&mut dot_file, "}}")); + Ok(()) +} diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index a55e2a42bc..e64354fb9d 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -1,190 +1,190 @@ -//! Intermediate representation for C/C++ enumerations. - -use super::context::{BindgenContext, ItemId}; -use super::item::Item; -use super::ty::TypeKind; -use clang; -use ir::annotations::Annotations; -use parse::{ClangItemParser, ParseError}; - -/// An enum representing custom handling that can be given to a variant. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum EnumVariantCustomBehavior { - /// This variant will be constified, that is, forced to generate a constant. - Constify, - /// This variant will be hidden entirely from the resulting enum. - Hide, -} - -/// A C/C++ enumeration. -#[derive(Debug)] -pub struct Enum { - /// The representation used for this enum; it should be an `IntKind` type or - /// an alias to one. - /// - /// It's `None` if the enum is a forward declaration and isn't defined - /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. - repr: Option, - - /// The different variants, with explicit values. - variants: Vec, -} - -impl Enum { - /// Construct a new `Enum` with the given representation and variants. - pub fn new(repr: Option, variants: Vec) -> Self { - Enum { - repr: repr, - variants: variants, - } - } - - /// Get this enumeration's representation. - pub fn repr(&self) -> Option { - self.repr - } - - /// Get this enumeration's variants. - pub fn variants(&self) -> &[EnumVariant] { - &self.variants - } - - /// Construct an enumeration from the given Clang type. - pub fn from_ty(ty: &clang::Type, - ctx: &mut BindgenContext) - -> Result { - use clang_sys::*; - debug!("Enum::from_ty {:?}", ty); - - if ty.kind() != CXType_Enum { - return Err(ParseError::Continue); - } - - let declaration = ty.declaration().canonical(); - let repr = declaration.enum_type() - .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); - let mut variants = vec![]; - - // Assume signedness since the default type by the C standard is an int. - let is_signed = - repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) - .map_or(true, |ty| match *ty.kind() { - TypeKind::Int(ref int_kind) => int_kind.is_signed(), - ref other => { - panic!("Since when enums can be non-integers? {:?}", - other) - } - }); - - let type_name = ty.spelling(); - let type_name = if type_name.is_empty() { - None - } else { - Some(type_name) - }; - let type_name = type_name.as_ref().map(String::as_str); - - let definition = declaration.definition().unwrap_or(declaration); - definition.visit(|cursor| { - if cursor.kind() == CXCursor_EnumConstantDecl { - let value = if is_signed { - cursor.enum_val_signed().map(EnumVariantValue::Signed) - } else { - cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) - }; - if let Some(val) = value { - let name = cursor.spelling(); - let custom_behavior = ctx.parse_callbacks() - .and_then(|t| { - t.enum_variant_behavior(type_name, &name, val) - }) - .or_else(|| { - Annotations::new(&cursor) - .and_then(|anno| if anno.hide() { - Some(EnumVariantCustomBehavior::Hide) - } else if - anno.constify_enum_variant() { - Some(EnumVariantCustomBehavior::Constify) - } else { - None - }) - }); - - let comment = cursor.raw_comment(); - variants.push(EnumVariant::new(name, - comment, - val, - custom_behavior)); - } - } - CXChildVisit_Continue - }); - Ok(Enum::new(repr, variants)) - } -} - -/// A single enum variant, to be contained only in an enum. -#[derive(Debug)] -pub struct EnumVariant { - /// The name of the variant. - name: String, - - /// An optional doc comment. - comment: Option, - - /// The integer value of the variant. - val: EnumVariantValue, - - /// The custom behavior this variant may have, if any. - custom_behavior: Option, -} - -/// A constant value assigned to an enumeration variant. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EnumVariantValue { - /// A signed constant. - Signed(i64), - - /// An unsigned constant. - Unsigned(u64), -} - -impl EnumVariant { - /// Construct a new enumeration variant from the given parts. - pub fn new(name: String, - comment: Option, - val: EnumVariantValue, - custom_behavior: Option) - -> Self { - EnumVariant { - name: name, - comment: comment, - val: val, - custom_behavior: custom_behavior, - } - } - - /// Get this variant's name. - pub fn name(&self) -> &str { - &self.name - } - - /// Get this variant's value. - pub fn val(&self) -> EnumVariantValue { - self.val - } - - /// Returns whether this variant should be enforced to be a constant by code - /// generation. - pub fn force_constification(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) - } - - /// Returns whether the current variant should be hidden completely from the - /// resulting rust enum. - pub fn hidden(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) - } -} +//! Intermediate representation for C/C++ enumerations. + +use super::context::{BindgenContext, ItemId}; +use super::item::Item; +use super::ty::TypeKind; +use clang; +use ir::annotations::Annotations; +use parse::{ClangItemParser, ParseError}; + +/// An enum representing custom handling that can be given to a variant. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum EnumVariantCustomBehavior { + /// This variant will be constified, that is, forced to generate a constant. + Constify, + /// This variant will be hidden entirely from the resulting enum. + Hide, +} + +/// A C/C++ enumeration. +#[derive(Debug)] +pub struct Enum { + /// The representation used for this enum; it should be an `IntKind` type or + /// an alias to one. + /// + /// It's `None` if the enum is a forward declaration and isn't defined + /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. + repr: Option, + + /// The different variants, with explicit values. + variants: Vec, +} + +impl Enum { + /// Construct a new `Enum` with the given representation and variants. + pub fn new(repr: Option, variants: Vec) -> Self { + Enum { + repr: repr, + variants: variants, + } + } + + /// Get this enumeration's representation. + pub fn repr(&self) -> Option { + self.repr + } + + /// Get this enumeration's variants. + pub fn variants(&self) -> &[EnumVariant] { + &self.variants + } + + /// Construct an enumeration from the given Clang type. + pub fn from_ty(ty: &clang::Type, + ctx: &mut BindgenContext) + -> Result { + use clang_sys::*; + debug!("Enum::from_ty {:?}", ty); + + if ty.kind() != CXType_Enum { + return Err(ParseError::Continue); + } + + let declaration = ty.declaration().canonical(); + let repr = declaration.enum_type() + .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); + let mut variants = vec![]; + + // Assume signedness since the default type by the C standard is an int. + let is_signed = + repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) + .map_or(true, |ty| match *ty.kind() { + TypeKind::Int(ref int_kind) => int_kind.is_signed(), + ref other => { + panic!("Since when enums can be non-integers? {:?}", + other) + } + }); + + let type_name = ty.spelling(); + let type_name = if type_name.is_empty() { + None + } else { + Some(type_name) + }; + let type_name = type_name.as_ref().map(String::as_str); + + let definition = declaration.definition().unwrap_or(declaration); + definition.visit(|cursor| { + if cursor.kind() == CXCursor_EnumConstantDecl { + let value = if is_signed { + cursor.enum_val_signed().map(EnumVariantValue::Signed) + } else { + cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) + }; + if let Some(val) = value { + let name = cursor.spelling(); + let custom_behavior = ctx.parse_callbacks() + .and_then(|t| { + t.enum_variant_behavior(type_name, &name, val) + }) + .or_else(|| { + Annotations::new(&cursor) + .and_then(|anno| if anno.hide() { + Some(EnumVariantCustomBehavior::Hide) + } else if + anno.constify_enum_variant() { + Some(EnumVariantCustomBehavior::Constify) + } else { + None + }) + }); + + let comment = cursor.raw_comment(); + variants.push(EnumVariant::new(name, + comment, + val, + custom_behavior)); + } + } + CXChildVisit_Continue + }); + Ok(Enum::new(repr, variants)) + } +} + +/// A single enum variant, to be contained only in an enum. +#[derive(Debug)] +pub struct EnumVariant { + /// The name of the variant. + name: String, + + /// An optional doc comment. + comment: Option, + + /// The integer value of the variant. + val: EnumVariantValue, + + /// The custom behavior this variant may have, if any. + custom_behavior: Option, +} + +/// A constant value assigned to an enumeration variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EnumVariantValue { + /// A signed constant. + Signed(i64), + + /// An unsigned constant. + Unsigned(u64), +} + +impl EnumVariant { + /// Construct a new enumeration variant from the given parts. + pub fn new(name: String, + comment: Option, + val: EnumVariantValue, + custom_behavior: Option) + -> Self { + EnumVariant { + name: name, + comment: comment, + val: val, + custom_behavior: custom_behavior, + } + } + + /// Get this variant's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variant's value. + pub fn val(&self) -> EnumVariantValue { + self.val + } + + /// Returns whether this variant should be enforced to be a constant by code + /// generation. + pub fn force_constification(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) + } + + /// Returns whether the current variant should be hidden completely from the + /// resulting rust enum. + pub fn hidden(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) + } +} diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs index 36fe5f37a9..419f9d4421 100644 --- a/src/ir/item_kind.rs +++ b/src/ir/item_kind.rs @@ -1,147 +1,147 @@ -//! Different variants of an `Item` in our intermediate representation. - -use super::context::BindgenContext; -use super::dot::DotAttributes; -use super::function::Function; -use super::module::Module; -use super::ty::Type; -use super::var::Var; -use std::io; - -/// A item we parse and translate. -#[derive(Debug)] -pub enum ItemKind { - /// A module, created implicitly once (the root module), or via C++ - /// namespaces. - Module(Module), - - /// A type declared in any of the multiple ways it can be declared. - Type(Type), - - /// A function or method declaration. - Function(Function), - - /// A variable declaration, most likely a static. - Var(Var), -} - -impl ItemKind { - /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it - /// is some other kind. - pub fn as_module(&self) -> Option<&Module> { - match *self { - ItemKind::Module(ref module) => Some(module), - _ => None, - } - } - - /// Transform our `ItemKind` into a string. - pub fn kind_name(&self) -> &'static str { - match *self { - ItemKind::Module(..) => "Module", - ItemKind::Type(..) => "Type", - ItemKind::Function(..) => "Function", - ItemKind::Var(..) => "Var", - } - } - - /// Is this a module? - pub fn is_module(&self) -> bool { - self.as_module().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it - /// is some other kind. - pub fn expect_module(&self) -> &Module { - self.as_module().expect("Not a module") - } - - /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if - /// it is some other kind. - pub fn as_function(&self) -> Option<&Function> { - match *self { - ItemKind::Function(ref func) => Some(func), - _ => None, - } - } - - /// Is this a function? - pub fn is_function(&self) -> bool { - self.as_function().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Function`, or panic if - /// it is some other kind. - pub fn expect_function(&self) -> &Function { - self.as_function().expect("Not a function") - } - - /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if - /// it is some other kind. - pub fn as_type(&self) -> Option<&Type> { - match *self { - ItemKind::Type(ref ty) => Some(ty), - _ => None, - } - } - - /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` - /// if it is some other kind. - pub fn as_type_mut(&mut self) -> Option<&mut Type> { - match *self { - ItemKind::Type(ref mut ty) => Some(ty), - _ => None, - } - } - - /// Is this a type? - pub fn is_type(&self) -> bool { - self.as_type().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is - /// some other kind. - pub fn expect_type(&self) -> &Type { - self.as_type().expect("Not a type") - } - - /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is - /// some other kind. - pub fn as_var(&self) -> Option<&Var> { - match *self { - ItemKind::Var(ref v) => Some(v), - _ => None, - } - } - - /// Is this a variable? - pub fn is_var(&self) -> bool { - self.as_var().is_some() - } - - /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is - /// some other kind. - pub fn expect_var(&self) -> &Var { - self.as_var().expect("Not a var") - } -} - -impl DotAttributes for ItemKind { - fn dot_attributes(&self, - ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - try!(writeln!(out, - "kind{}", - self.kind_name())); - - match *self { - ItemKind::Module(ref module) => module.dot_attributes(ctx, out), - ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out), - ItemKind::Function(ref func) => func.dot_attributes(ctx, out), - ItemKind::Var(ref var) => var.dot_attributes(ctx, out), - } - } -} +//! Different variants of an `Item` in our intermediate representation. + +use super::context::BindgenContext; +use super::dot::DotAttributes; +use super::function::Function; +use super::module::Module; +use super::ty::Type; +use super::var::Var; +use std::io; + +/// A item we parse and translate. +#[derive(Debug)] +pub enum ItemKind { + /// A module, created implicitly once (the root module), or via C++ + /// namespaces. + Module(Module), + + /// A type declared in any of the multiple ways it can be declared. + Type(Type), + + /// A function or method declaration. + Function(Function), + + /// A variable declaration, most likely a static. + Var(Var), +} + +impl ItemKind { + /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it + /// is some other kind. + pub fn as_module(&self) -> Option<&Module> { + match *self { + ItemKind::Module(ref module) => Some(module), + _ => None, + } + } + + /// Transform our `ItemKind` into a string. + pub fn kind_name(&self) -> &'static str { + match *self { + ItemKind::Module(..) => "Module", + ItemKind::Type(..) => "Type", + ItemKind::Function(..) => "Function", + ItemKind::Var(..) => "Var", + } + } + + /// Is this a module? + pub fn is_module(&self) -> bool { + self.as_module().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it + /// is some other kind. + pub fn expect_module(&self) -> &Module { + self.as_module().expect("Not a module") + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if + /// it is some other kind. + pub fn as_function(&self) -> Option<&Function> { + match *self { + ItemKind::Function(ref func) => Some(func), + _ => None, + } + } + + /// Is this a function? + pub fn is_function(&self) -> bool { + self.as_function().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or panic if + /// it is some other kind. + pub fn expect_function(&self) -> &Function { + self.as_function().expect("Not a function") + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if + /// it is some other kind. + pub fn as_type(&self) -> Option<&Type> { + match *self { + ItemKind::Type(ref ty) => Some(ty), + _ => None, + } + } + + /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` + /// if it is some other kind. + pub fn as_type_mut(&mut self) -> Option<&mut Type> { + match *self { + ItemKind::Type(ref mut ty) => Some(ty), + _ => None, + } + } + + /// Is this a type? + pub fn is_type(&self) -> bool { + self.as_type().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is + /// some other kind. + pub fn expect_type(&self) -> &Type { + self.as_type().expect("Not a type") + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is + /// some other kind. + pub fn as_var(&self) -> Option<&Var> { + match *self { + ItemKind::Var(ref v) => Some(v), + _ => None, + } + } + + /// Is this a variable? + pub fn is_var(&self) -> bool { + self.as_var().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is + /// some other kind. + pub fn expect_var(&self) -> &Var { + self.as_var().expect("Not a var") + } +} + +impl DotAttributes for ItemKind { + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + try!(writeln!(out, + "kind{}", + self.kind_name())); + + match *self { + ItemKind::Module(ref module) => module.dot_attributes(ctx, out), + ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out), + ItemKind::Function(ref func) => func.dot_attributes(ctx, out), + ItemKind::Var(ref var) => var.dot_attributes(ctx, out), + } + } +} diff --git a/src/ir/layout.rs b/src/ir/layout.rs index 58d6dc615f..21382b2d99 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -1,134 +1,134 @@ -//! Intermediate representation for the physical layout of some type. - -use super::context::BindgenContext; -use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; -use clang; -use std::{cmp, mem}; - -/// A type that represents the struct layout of a type. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Layout { - /// The size (in bytes) of this layout. - pub size: usize, - /// The alignment (in bytes) of this layout. - pub align: usize, - /// Whether this layout's members are packed or not. - pub packed: bool, -} - -#[test] -fn test_layout_for_size() { - let ptr_size = mem::size_of::<*mut ()>(); - assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size)); - assert_eq!(Layout::for_size(3 * ptr_size), - Layout::new(3 * ptr_size, ptr_size)); -} - -impl Layout { - /// Construct a new `Layout` with the given `size` and `align`. It is not - /// packed. - pub fn new(size: usize, align: usize) -> Self { - Layout { - size: size, - align: align, - packed: false, - } - } - - /// Creates a non-packed layout for a given size, trying to use the maximum - /// alignment possible. - pub fn for_size(size: usize) -> Self { - let mut next_align = 2; - while size % next_align == 0 && - next_align <= mem::size_of::<*mut ()>() { - next_align *= 2; - } - Layout { - size: size, - align: next_align / 2, - packed: false, - } - } - - /// Is this a zero-sized layout? - pub fn is_zero(&self) -> bool { - self.size == 0 && self.align == 0 - } - - /// Construct a zero-sized layout. - pub fn zero() -> Self { - Self::new(0, 0) - } - - /// Get this layout as an opaque type. - pub fn opaque(&self) -> Opaque { - Opaque(*self) - } -} - -/// When we are treating a type as opaque, it is just a blob with a `Layout`. -#[derive(Clone, Debug, PartialEq)] -pub struct Opaque(pub Layout); - -impl Opaque { - /// Construct a new opaque type from the given clang type. - pub fn from_clang_ty(ty: &clang::Type) -> Type { - let layout = Layout::new(ty.size(), ty.align()); - let ty_kind = TypeKind::Opaque; - Type::new(None, Some(layout), ty_kind, false) - } - - /// Return the known rust type we should use to create a correctly-aligned - /// field with this layout. - pub fn known_rust_type_for_array(&self) -> Option<&'static str> { - Some(match self.0.align { - 8 => "u64", - 4 => "u32", - 2 => "u16", - 1 => "u8", - _ => return None, - }) - } - - /// Return the array size that an opaque type for this layout should have if - /// we know the correct type for it, or `None` otherwise. - pub fn array_size(&self) -> Option { - if self.known_rust_type_for_array().is_some() { - Some(self.0.size / cmp::max(self.0.align, 1)) - } else { - None - } - } -} - -impl CanDeriveDebug for Opaque { - type Extra = (); - - fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } -} - -impl CanDeriveDefault for Opaque { - type Extra = (); - - fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } -} - -impl<'a> CanDeriveCopy<'a> for Opaque { - type Extra = (); - - fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool { - self.array_size() - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - } - - fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { - self.can_derive_copy(ctx, ()) - } -} +//! Intermediate representation for the physical layout of some type. + +use super::context::BindgenContext; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; +use clang; +use std::{cmp, mem}; + +/// A type that represents the struct layout of a type. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Layout { + /// The size (in bytes) of this layout. + pub size: usize, + /// The alignment (in bytes) of this layout. + pub align: usize, + /// Whether this layout's members are packed or not. + pub packed: bool, +} + +#[test] +fn test_layout_for_size() { + let ptr_size = mem::size_of::<*mut ()>(); + assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size)); + assert_eq!(Layout::for_size(3 * ptr_size), + Layout::new(3 * ptr_size, ptr_size)); +} + +impl Layout { + /// Construct a new `Layout` with the given `size` and `align`. It is not + /// packed. + pub fn new(size: usize, align: usize) -> Self { + Layout { + size: size, + align: align, + packed: false, + } + } + + /// Creates a non-packed layout for a given size, trying to use the maximum + /// alignment possible. + pub fn for_size(size: usize) -> Self { + let mut next_align = 2; + while size % next_align == 0 && + next_align <= mem::size_of::<*mut ()>() { + next_align *= 2; + } + Layout { + size: size, + align: next_align / 2, + packed: false, + } + } + + /// Is this a zero-sized layout? + pub fn is_zero(&self) -> bool { + self.size == 0 && self.align == 0 + } + + /// Construct a zero-sized layout. + pub fn zero() -> Self { + Self::new(0, 0) + } + + /// Get this layout as an opaque type. + pub fn opaque(&self) -> Opaque { + Opaque(*self) + } +} + +/// When we are treating a type as opaque, it is just a blob with a `Layout`. +#[derive(Clone, Debug, PartialEq)] +pub struct Opaque(pub Layout); + +impl Opaque { + /// Construct a new opaque type from the given clang type. + pub fn from_clang_ty(ty: &clang::Type) -> Type { + let layout = Layout::new(ty.size(), ty.align()); + let ty_kind = TypeKind::Opaque; + Type::new(None, Some(layout), ty_kind, false) + } + + /// Return the known rust type we should use to create a correctly-aligned + /// field with this layout. + pub fn known_rust_type_for_array(&self) -> Option<&'static str> { + Some(match self.0.align { + 8 => "u64", + 4 => "u32", + 2 => "u16", + 1 => "u8", + _ => return None, + }) + } + + /// Return the array size that an opaque type for this layout should have if + /// we know the correct type for it, or `None` otherwise. + pub fn array_size(&self) -> Option { + if self.known_rust_type_for_array().is_some() { + Some(self.0.size / cmp::max(self.0.align, 1)) + } else { + None + } + } +} + +impl CanDeriveDebug for Opaque { + type Extra = (); + + fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + +impl CanDeriveDefault for Opaque { + type Extra = (); + + fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + +impl<'a> CanDeriveCopy<'a> for Opaque { + type Extra = (); + + fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } + + fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { + self.can_derive_copy(ctx, ()) + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs index c4f2ccae53..d703e53dbb 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,23 +1,23 @@ -//! The ir module defines bindgen's intermediate representation. -//! -//! Parsing C/C++ generates the IR, while code generation outputs Rust code from -//! the IR. - -pub mod annotations; -pub mod comp; -pub mod context; -pub mod derive; -pub mod dot; -pub mod enum_ty; -pub mod function; -pub mod int; -pub mod item; -pub mod item_kind; -pub mod layout; -pub mod module; -pub mod named; -pub mod template; -pub mod traversal; -pub mod ty; -pub mod var; -pub mod objc; +//! The ir module defines bindgen's intermediate representation. +//! +//! Parsing C/C++ generates the IR, while code generation outputs Rust code from +//! the IR. + +pub mod annotations; +pub mod comp; +pub mod context; +pub mod derive; +pub mod dot; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod named; +pub mod template; +pub mod traversal; +pub mod ty; +pub mod var; +pub mod objc; diff --git a/src/ir/module.rs b/src/ir/module.rs index 292cbb6b40..ee3912c5f1 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,91 +1,91 @@ -//! Intermediate representation for modules (AKA C++ namespaces). - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use clang; -use parse::{ClangSubItemParser, ParseError, ParseResult}; -use parse_one; -use std::io; - -/// Whether this module is inline or not. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ModuleKind { - /// This module is not inline. - Normal, - /// This module is inline, as in `inline namespace foo {}`. - Inline, -} - -/// A module, as in, a C++ namespace. -#[derive(Clone, Debug)] -pub struct Module { - /// The name of the module, or none if it's anonymous. - name: Option, - /// The kind of module this is. - kind: ModuleKind, - /// The children of this module, just here for convenience. - children_ids: Vec, -} - -impl Module { - /// Construct a new `Module`. - pub fn new(name: Option, kind: ModuleKind) -> Self { - Module { - name: name, - kind: kind, - children_ids: vec![], - } - } - - /// Get this module's name. - pub fn name(&self) -> Option<&str> { - self.name.as_ref().map(|n| &**n) - } - - /// Get a mutable reference to this module's children. - pub fn children_mut(&mut self) -> &mut Vec { - &mut self.children_ids - } - - /// Get this module's children. - pub fn children(&self) -> &[ItemId] { - &self.children_ids - } - - /// Whether this namespace is inline. - pub fn is_inline(&self) -> bool { - self.kind == ModuleKind::Inline - } -} - -impl DotAttributes for Module { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - writeln!(out, "ModuleKind{:?}", self.kind) - } -} - -impl ClangSubItemParser for Module { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - match cursor.kind() { - CXCursor_Namespace => { - let module_id = ctx.module(cursor); - ctx.with_module(module_id, |ctx| { - cursor.visit(|cursor| { - parse_one(ctx, cursor, Some(module_id)) - }) - }); - - Ok(ParseResult::AlreadyResolved(module_id)) - } - _ => Err(ParseError::Continue), - } - } -} +//! Intermediate representation for modules (AKA C++ namespaces). + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; +use std::io; + +/// Whether this module is inline or not. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ModuleKind { + /// This module is not inline. + Normal, + /// This module is inline, as in `inline namespace foo {}`. + Inline, +} + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option, + /// The kind of module this is. + kind: ModuleKind, + /// The children of this module, just here for convenience. + children_ids: Vec, +} + +impl Module { + /// Construct a new `Module`. + pub fn new(name: Option, kind: ModuleKind) -> Self { + Module { + name: name, + kind: kind, + children_ids: vec![], + } + } + + /// Get this module's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get a mutable reference to this module's children. + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children_ids + } + + /// Get this module's children. + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } + + /// Whether this namespace is inline. + pub fn is_inline(&self) -> bool { + self.kind == ModuleKind::Inline + } +} + +impl DotAttributes for Module { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + writeln!(out, "ModuleKind{:?}", self.kind) + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx| { + cursor.visit(|cursor| { + parse_one(ctx, cursor, Some(module_id)) + }) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue), + } + } +} diff --git a/src/ir/objc.rs b/src/ir/objc.rs index 7b6227431f..3a88eef8ab 100644 --- a/src/ir/objc.rs +++ b/src/ir/objc.rs @@ -1,254 +1,254 @@ -//! Objective C types - -use super::context::{BindgenContext, ItemId}; -use super::function::FunctionSig; -use super::traversal::{Trace, Tracer}; -use super::ty::TypeKind; -use clang; -use clang_sys::CXChildVisit_Continue; -use clang_sys::CXCursor_ObjCCategoryDecl; -use clang_sys::CXCursor_ObjCClassMethodDecl; -use clang_sys::CXCursor_ObjCClassRef; -use clang_sys::CXCursor_ObjCInstanceMethodDecl; -use clang_sys::CXCursor_ObjCProtocolDecl; -use clang_sys::CXCursor_ObjCProtocolRef; - -/// Objective C interface as used in TypeKind -/// -/// Also protocols and categories are parsed as this type -#[derive(Debug)] -pub struct ObjCInterface { - /// The name - /// like, NSObject - name: String, - - category: Option, - - is_protocol: bool, - - conforms_to: Vec, - - /// List of the methods defined in this interfae - methods: Vec, - - class_methods: Vec, -} - -/// The objective c methods -#[derive(Debug)] -pub struct ObjCMethod { - /// The original method selector name - /// like, dataWithBytes:length: - name: String, - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - rust_name: String, - - signature: FunctionSig, - - /// Is class method? - is_class_method: bool, -} - -impl ObjCInterface { - fn new(name: &str) -> ObjCInterface { - ObjCInterface { - name: name.to_owned(), - category: None, - is_protocol: false, - conforms_to: Vec::new(), - methods: Vec::new(), - class_methods: Vec::new(), - } - } - - /// The name - /// like, NSObject - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Formats the name for rust - /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods - /// and protocols are like protocol_NSObject - pub fn rust_name(&self) -> String { - if let Some(ref cat) = self.category { - format!("{}_{}", self.name(), cat) - } else { - if self.is_protocol { - format!("protocol_{}", self.name()) - } else { - self.name().to_owned() - } - } - } - - /// List of the methods defined in this interface - pub fn methods(&self) -> &Vec { - &self.methods - } - - /// List of the class methods defined in this interface - pub fn class_methods(&self) -> &Vec { - &self.class_methods - } - - /// Parses the Objective C interface from the cursor - pub fn from_ty(cursor: &clang::Cursor, - ctx: &mut BindgenContext) - -> Option { - let name = cursor.spelling(); - let mut interface = Self::new(&name); - - if cursor.kind() == CXCursor_ObjCProtocolDecl { - interface.is_protocol = true; - } - - cursor.visit(|c| { - match c.kind() { - CXCursor_ObjCClassRef => { - if cursor.kind() == CXCursor_ObjCCategoryDecl { - // We are actually a category extension, and we found the reference - // to the original interface, so name this interface approriately - interface.name = c.spelling(); - interface.category = Some(cursor.spelling()); - } - } - CXCursor_ObjCProtocolRef => { - // Gather protocols this interface conforms to - let needle = format!("protocol_{}", c.spelling()); - let items_map = ctx.items(); - debug!("Interface {} conforms to {}, find the item", interface.name, needle); - - for (id, item) in items_map - { - if let Some(ty) = item.as_type() { - match *ty.kind() { - TypeKind::ObjCInterface(ref protocol) => { - if protocol.is_protocol - { - debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); - if Some(needle.as_ref()) == ty.name() - { - debug!("Found conforming protocol {:?}", item); - interface.conforms_to.push(*id); - break; - } - } - } - _ => {} - } - } - } - - } - CXCursor_ObjCInstanceMethodDecl | - CXCursor_ObjCClassMethodDecl => { - let name = c.spelling(); - let signature = - FunctionSig::from_ty(&c.cur_type(), &c, ctx) - .expect("Invalid function sig"); - let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; - let method = ObjCMethod::new(&name, signature, is_class_method); - interface.add_method(method); - } - _ => {} - } - CXChildVisit_Continue - }); - Some(interface) - } - - fn add_method(&mut self, method: ObjCMethod) { - if method.is_class_method { - self.class_methods.push(method); - } else { - self.methods.push(method); - } - } -} - -impl ObjCMethod { - fn new(name: &str, - signature: FunctionSig, - is_class_method: bool) - -> ObjCMethod { - let split_name: Vec<&str> = name.split(':').collect(); - - let rust_name = split_name.join("_"); - - ObjCMethod { - name: name.to_owned(), - rust_name: rust_name.to_owned(), - signature: signature, - is_class_method: is_class_method, - } - } - - /// The original method selector name - /// like, dataWithBytes:length: - pub fn name(&self) -> &str { - self.name.as_ref() - } - - /// Method name as converted to rust - /// like, dataWithBytes_length_ - pub fn rust_name(&self) -> &str { - self.rust_name.as_ref() - } - - /// Returns the methods signature as FunctionSig - pub fn signature(&self) -> &FunctionSig { - &self.signature - } - - /// Is this a class method? - pub fn is_class_method(&self) -> bool { - self.is_class_method - } - - /// Formats the method call - pub fn format_method_call(&self, args: &[String]) -> String { - let split_name: Vec<&str> = - self.name.split(':').filter(|p| !p.is_empty()).collect(); - - // No arguments - if args.len() == 0 && split_name.len() == 1 { - return split_name[0].to_string(); - } - - // Check right amount of arguments - if args.len() != split_name.len() { - panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", - args, - split_name); - } - - split_name.iter() - .zip(args.iter()) - .map(|parts| format!("{}:{} ", parts.0, parts.1)) - .collect::>() - .join("") - } -} - -impl Trace for ObjCInterface { - type Extra = (); - - fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) - where T: Tracer, - { - for method in &self.methods { - method.signature.trace(context, tracer, &()); - } - - for class_method in &self.class_methods { - class_method.signature.trace(context, tracer, &()); - } - - for protocol in &self.conforms_to { - tracer.visit(*protocol); - } - } -} +//! Objective C types + +use super::context::{BindgenContext, ItemId}; +use super::function::FunctionSig; +use super::traversal::{Trace, Tracer}; +use super::ty::TypeKind; +use clang; +use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCCategoryDecl; +use clang_sys::CXCursor_ObjCClassMethodDecl; +use clang_sys::CXCursor_ObjCClassRef; +use clang_sys::CXCursor_ObjCInstanceMethodDecl; +use clang_sys::CXCursor_ObjCProtocolDecl; +use clang_sys::CXCursor_ObjCProtocolRef; + +/// Objective C interface as used in TypeKind +/// +/// Also protocols and categories are parsed as this type +#[derive(Debug)] +pub struct ObjCInterface { + /// The name + /// like, NSObject + name: String, + + category: Option, + + is_protocol: bool, + + conforms_to: Vec, + + /// List of the methods defined in this interfae + methods: Vec, + + class_methods: Vec, +} + +/// The objective c methods +#[derive(Debug)] +pub struct ObjCMethod { + /// The original method selector name + /// like, dataWithBytes:length: + name: String, + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + rust_name: String, + + signature: FunctionSig, + + /// Is class method? + is_class_method: bool, +} + +impl ObjCInterface { + fn new(name: &str) -> ObjCInterface { + ObjCInterface { + name: name.to_owned(), + category: None, + is_protocol: false, + conforms_to: Vec::new(), + methods: Vec::new(), + class_methods: Vec::new(), + } + } + + /// The name + /// like, NSObject + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + /// and protocols are like protocol_NSObject + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + if self.is_protocol { + format!("protocol_{}", self.name()) + } else { + self.name().to_owned() + } + } + } + + /// List of the methods defined in this interface + pub fn methods(&self) -> &Vec { + &self.methods + } + + /// List of the class methods defined in this interface + pub fn class_methods(&self) -> &Vec { + &self.class_methods + } + + /// Parses the Objective C interface from the cursor + pub fn from_ty(cursor: &clang::Cursor, + ctx: &mut BindgenContext) + -> Option { + let name = cursor.spelling(); + let mut interface = Self::new(&name); + + if cursor.kind() == CXCursor_ObjCProtocolDecl { + interface.is_protocol = true; + } + + cursor.visit(|c| { + match c.kind() { + CXCursor_ObjCClassRef => { + if cursor.kind() == CXCursor_ObjCCategoryDecl { + // We are actually a category extension, and we found the reference + // to the original interface, so name this interface approriately + interface.name = c.spelling(); + interface.category = Some(cursor.spelling()); + } + } + CXCursor_ObjCProtocolRef => { + // Gather protocols this interface conforms to + let needle = format!("protocol_{}", c.spelling()); + let items_map = ctx.items(); + debug!("Interface {} conforms to {}, find the item", interface.name, needle); + + for (id, item) in items_map + { + if let Some(ty) = item.as_type() { + match *ty.kind() { + TypeKind::ObjCInterface(ref protocol) => { + if protocol.is_protocol + { + debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); + if Some(needle.as_ref()) == ty.name() + { + debug!("Found conforming protocol {:?}", item); + interface.conforms_to.push(*id); + break; + } + } + } + _ => {} + } + } + } + + } + CXCursor_ObjCInstanceMethodDecl | + CXCursor_ObjCClassMethodDecl => { + let name = c.spelling(); + let signature = + FunctionSig::from_ty(&c.cur_type(), &c, ctx) + .expect("Invalid function sig"); + let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; + let method = ObjCMethod::new(&name, signature, is_class_method); + interface.add_method(method); + } + _ => {} + } + CXChildVisit_Continue + }); + Some(interface) + } + + fn add_method(&mut self, method: ObjCMethod) { + if method.is_class_method { + self.class_methods.push(method); + } else { + self.methods.push(method); + } + } +} + +impl ObjCMethod { + fn new(name: &str, + signature: FunctionSig, + is_class_method: bool) + -> ObjCMethod { + let split_name: Vec<&str> = name.split(':').collect(); + + let rust_name = split_name.join("_"); + + ObjCMethod { + name: name.to_owned(), + rust_name: rust_name.to_owned(), + signature: signature, + is_class_method: is_class_method, + } + } + + /// The original method selector name + /// like, dataWithBytes:length: + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + pub fn rust_name(&self) -> &str { + self.rust_name.as_ref() + } + + /// Returns the methods signature as FunctionSig + pub fn signature(&self) -> &FunctionSig { + &self.signature + } + + /// Is this a class method? + pub fn is_class_method(&self) -> bool { + self.is_class_method + } + + /// Formats the method call + pub fn format_method_call(&self, args: &[String]) -> String { + let split_name: Vec<&str> = + self.name.split(':').filter(|p| !p.is_empty()).collect(); + + // No arguments + if args.len() == 0 && split_name.len() == 1 { + return split_name[0].to_string(); + } + + // Check right amount of arguments + if args.len() != split_name.len() { + panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", + args, + split_name); + } + + split_name.iter() + .zip(args.iter()) + .map(|parts| format!("{}:{} ", parts.0, parts.1)) + .collect::>() + .join("") + } +} + +impl Trace for ObjCInterface { + type Extra = (); + + fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) + where T: Tracer, + { + for method in &self.methods { + method.signature.trace(context, tracer, &()); + } + + for class_method in &self.class_methods { + class_method.signature.trace(context, tracer, &()); + } + + for protocol in &self.conforms_to { + tracer.visit(*protocol); + } + } +} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index 2ee75a9a6d..95d2a45675 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -1,476 +1,476 @@ -//! Traversal of the graph of IR items and types. - -use super::context::{BindgenContext, ItemId}; -use super::item::ItemSet; -use std::collections::{BTreeMap, VecDeque}; - -/// An outgoing edge in the IR graph is a reference from some item to another -/// item: -/// -/// from --> to -/// -/// The `from` is left implicit: it is the concrete `Trace` implementor which -/// yielded this outgoing edge. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Edge { - to: ItemId, - kind: EdgeKind, -} - -impl Edge { - /// Construct a new edge whose referent is `to` and is of the given `kind`. - pub fn new(to: ItemId, kind: EdgeKind) -> Edge { - Edge { - to: to, - kind: kind, - } - } - - /// Get the item that this edge is pointing to. - pub fn to(&self) -> ItemId { - self.to - } - - /// Get the kind of edge that this is. - pub fn kind(&self) -> EdgeKind { - self.kind - } -} - -impl Into for Edge { - fn into(self) -> ItemId { - self.to - } -} - -/// The kind of edge reference. This is useful when we wish to only consider -/// certain kinds of edges for a particular traversal or analysis. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EdgeKind { - /// A generic, catch-all edge. - Generic, - - /// An edge from a template declaration, to the definition of a named type - /// parameter. For example, the edge from `Foo` to `T` in the following - /// snippet: - /// - /// ```C++ - /// template - /// class Foo { }; - /// ``` - TemplateParameterDefinition, - - /// An edge from a template instantiation to the template declaration that - /// is being instantiated. For example, the edge from `Foo` to - /// to `Foo`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// using Bar = Foo; - /// ``` - TemplateDeclaration, - - /// An edge from a template instantiation to its template argument. For - /// example, `Foo` to `Bar`: - /// - /// ```C++ - /// template - /// class Foo { }; - /// - /// class Bar { }; - /// - /// using FooBar = Foo; - /// ``` - TemplateArgument, - - /// An edge from a compound type to one of its base member types. For - /// example, the edge from `Bar` to `Foo`: - /// - /// ```C++ - /// class Foo { }; - /// - /// class Bar : public Foo { }; - /// ``` - BaseMember, - - /// An edge from a compound type to the types of one of its fields. For - /// example, the edge from `Foo` to `int`: - /// - /// ```C++ - /// class Foo { - /// int x; - /// }; - /// ``` - Field, - - /// An edge from an class or struct type to an inner type member. For - /// example, the edge from `Foo` to `Foo::Bar` here: - /// - /// ```C++ - /// class Foo { - /// struct Bar { }; - /// }; - /// ``` - InnerType, - - /// An edge from an class or struct type to an inner static variable. For - /// example, the edge from `Foo` to `Foo::BAR` here: - /// - /// ```C++ - /// class Foo { - /// static const char* BAR; - /// }; - /// ``` - InnerVar, - - /// An edge from a class or struct type to one of its method functions. For - /// example, the edge from `Foo` to `Foo::bar`: - /// - /// ```C++ - /// class Foo { - /// bool bar(int x, int y); - /// }; - /// ``` - Method, - - /// An edge from a class or struct type to one of its constructor - /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: - /// - /// ```C++ - /// class Foo { - /// int my_x; - /// int my_y; - /// - /// public: - /// Foo(int x, int y); - /// }; - /// ``` - Constructor, - - /// An edge from a function declaration to its return type. For example, the - /// edge from `foo` to `int`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionReturn, - - /// An edge from a function declaration to one of its parameter types. For - /// example, the edge from `foo` to `char*`: - /// - /// ```C++ - /// int foo(char* string); - /// ``` - FunctionParameter, - - /// An edge from a static variable to its type. For example, the edge from - /// `FOO` to `const char*`: - /// - /// ```C++ - /// static const char* FOO; - /// ``` - VarType, - - /// An edge from a non-templated alias or typedef to the referenced type. - TypeReference, -} - -/// A predicate to allow visiting only sub-sets of the whole IR graph by -/// excluding certain edges from being followed by the traversal. -pub trait TraversalPredicate { - /// Should the traversal follow this edge, and visit everything that is - /// reachable through it? - fn should_follow(&self, edge: Edge) -> bool; -} - -impl TraversalPredicate for fn(Edge) -> bool { - fn should_follow(&self, edge: Edge) -> bool { - (*self)(edge) - } -} - -/// A `TraversalPredicate` implementation that follows all edges, and therefore -/// traversals using this predicate will see the whole IR graph reachable from -/// the traversal's roots. -pub fn all_edges(_: Edge) -> bool { - true -} - -/// A `TraversalPredicate` implementation that never follows any edges, and -/// therefore traversals using this predicate will only visit the traversal's -/// roots. -pub fn no_edges(_: Edge) -> bool { - false -} - -/// The storage for the set of items that have been seen (although their -/// outgoing edges might not have been fully traversed yet) in an active -/// traversal. -pub trait TraversalStorage<'ctx, 'gen> { - /// Construct a new instance of this TraversalStorage, for a new traversal. - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; - - /// Add the given item to the storage. If the item has never been seen - /// before, return `true`. Otherwise, return `false`. - /// - /// The `from` item is the item from which we discovered this item, or is - /// `None` if this item is a root. - fn add(&mut self, from: Option, item: ItemId) -> bool; -} - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { - fn new(_: &'ctx BindgenContext<'gen>) -> Self { - ItemSet::new() - } - - fn add(&mut self, _: Option, item: ItemId) -> bool { - self.insert(item) - } -} - -/// A `TraversalStorage` implementation that keeps track of how we first reached -/// each item. This is useful for providing debug assertions with meaningful -/// diagnostic messages about dangling items. -#[derive(Debug)] -pub struct Paths<'ctx, 'gen>(BTreeMap, - &'ctx BindgenContext<'gen>) - where 'gen: 'ctx; - -impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> - where 'gen: 'ctx, -{ - fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { - Paths(BTreeMap::new(), ctx) - } - - fn add(&mut self, from: Option, item: ItemId) -> bool { - let newly_discovered = - self.0.insert(item, from.unwrap_or(item)).is_none(); - - if self.1.resolve_item_fallible(item).is_none() { - let mut path = vec![]; - let mut current = item; - loop { - let predecessor = *self.0 - .get(¤t) - .expect("We know we found this item id, so it must have a \ - predecessor"); - if predecessor == current { - break; - } - path.push(predecessor); - current = predecessor; - } - path.reverse(); - panic!("Found reference to dangling id = {:?}\nvia path = {:?}", - item, - path); - } - - newly_discovered - } -} - -/// The queue of seen-but-not-yet-traversed items. -/// -/// Using a FIFO queue with a traversal will yield a breadth-first traversal, -/// while using a LIFO queue will result in a depth-first traversal of the IR -/// graph. -pub trait TraversalQueue: Default { - /// Add a newly discovered item to the queue. - fn push(&mut self, item: ItemId); - - /// Pop the next item to traverse, if any. - fn next(&mut self) -> Option; -} - -impl TraversalQueue for Vec { - fn push(&mut self, item: ItemId) { - self.push(item); - } - - fn next(&mut self) -> Option { - self.pop() - } -} - -impl TraversalQueue for VecDeque { - fn push(&mut self, item: ItemId) { - self.push_back(item); - } - - fn next(&mut self) -> Option { - self.pop_front() - } -} - -/// Something that can receive edges from a `Trace` implementation. -pub trait Tracer { - /// Note an edge between items. Called from within a `Trace` implementation. - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); - - /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. - fn visit(&mut self, item: ItemId) { - self.visit_kind(item, EdgeKind::Generic); - } -} - -impl Tracer for F - where F: FnMut(ItemId, EdgeKind), -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - (*self)(item, kind) - } -} - -/// Trace all of the outgoing edges to other items. Implementations should call -/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` -/// for each of their outgoing edges. -pub trait Trace { - /// If a particular type needs extra information beyond what it has in - /// `self` and `context` to find its referenced items, its implementation - /// can define this associated type, forcing callers to pass the needed - /// information through. - type Extra; - - /// Trace all of this item's outgoing edges to other items. - fn trace(&self, - context: &BindgenContext, - tracer: &mut T, - extra: &Self::Extra) - where T: Tracer; -} - -/// An graph traversal of the transitive closure of references between items. -/// -/// See `BindgenContext::whitelisted_items` for more information. -pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - ctx: &'ctx BindgenContext<'gen>, - - /// The set of items we have seen thus far in this traversal. - seen: Storage, - - /// The set of items that we have seen, but have yet to traverse. - queue: Queue, - - /// The predicate that determins which edges this traversal will follow. - predicate: Predicate, - - /// The item we are currently traversing. - currently_traversing: Option, -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, - 'gen, - Storage, - Queue, - Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - /// Begin a new traversal, starting from the given roots. - pub fn new(ctx: &'ctx BindgenContext<'gen>, - roots: R, - predicate: Predicate) - -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where R: IntoIterator, - { - let mut seen = Storage::new(ctx); - let mut queue = Queue::default(); - - for id in roots { - seen.add(None, id); - queue.push(id); - } - - ItemTraversal { - ctx: ctx, - seen: seen, - queue: queue, - predicate: predicate, - currently_traversing: None, - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - let edge = Edge::new(item, kind); - if !self.predicate.should_follow(edge) { - return; - } - - let is_newly_discovered = self.seen - .add(self.currently_traversing, item); - if is_newly_discovered { - self.queue.push(item) - } - } -} - -impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator - for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> - where 'gen: 'ctx, - Storage: TraversalStorage<'ctx, 'gen>, - Queue: TraversalQueue, - Predicate: TraversalPredicate, -{ - type Item = ItemId; - - fn next(&mut self) -> Option { - let id = match self.queue.next() { - None => return None, - Some(id) => id, - }; - - let newly_discovered = self.seen.add(None, id); - debug_assert!(!newly_discovered, - "should have already seen anything we get out of our queue"); - debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), - "should only get IDs of actual items in our context during traversal"); - - self.currently_traversing = Some(id); - id.trace(self.ctx, self, &()); - self.currently_traversing = None; - - Some(id) - } -} - -/// An iterator to find any dangling items. -/// -/// See `BindgenContext::assert_no_dangling_item_traversal` for more -/// information. -pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = - ItemTraversal<'ctx, - 'gen, - Paths<'ctx, 'gen>, - VecDeque, - fn(Edge) -> bool>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[allow(dead_code)] - fn traversal_predicate_is_object_safe() { - // This should compile only if TraversalPredicate is object safe. - fn takes_by_trait_object(_: &TraversalPredicate) {} - } -} +//! Traversal of the graph of IR items and types. + +use super::context::{BindgenContext, ItemId}; +use super::item::ItemSet; +use std::collections::{BTreeMap, VecDeque}; + +/// An outgoing edge in the IR graph is a reference from some item to another +/// item: +/// +/// from --> to +/// +/// The `from` is left implicit: it is the concrete `Trace` implementor which +/// yielded this outgoing edge. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Edge { + to: ItemId, + kind: EdgeKind, +} + +impl Edge { + /// Construct a new edge whose referent is `to` and is of the given `kind`. + pub fn new(to: ItemId, kind: EdgeKind) -> Edge { + Edge { + to: to, + kind: kind, + } + } + + /// Get the item that this edge is pointing to. + pub fn to(&self) -> ItemId { + self.to + } + + /// Get the kind of edge that this is. + pub fn kind(&self) -> EdgeKind { + self.kind + } +} + +impl Into for Edge { + fn into(self) -> ItemId { + self.to + } +} + +/// The kind of edge reference. This is useful when we wish to only consider +/// certain kinds of edges for a particular traversal or analysis. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EdgeKind { + /// A generic, catch-all edge. + Generic, + + /// An edge from a template declaration, to the definition of a named type + /// parameter. For example, the edge from `Foo` to `T` in the following + /// snippet: + /// + /// ```C++ + /// template + /// class Foo { }; + /// ``` + TemplateParameterDefinition, + + /// An edge from a template instantiation to the template declaration that + /// is being instantiated. For example, the edge from `Foo` to + /// to `Foo`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// using Bar = Foo; + /// ``` + TemplateDeclaration, + + /// An edge from a template instantiation to its template argument. For + /// example, `Foo` to `Bar`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// class Bar { }; + /// + /// using FooBar = Foo; + /// ``` + TemplateArgument, + + /// An edge from a compound type to one of its base member types. For + /// example, the edge from `Bar` to `Foo`: + /// + /// ```C++ + /// class Foo { }; + /// + /// class Bar : public Foo { }; + /// ``` + BaseMember, + + /// An edge from a compound type to the types of one of its fields. For + /// example, the edge from `Foo` to `int`: + /// + /// ```C++ + /// class Foo { + /// int x; + /// }; + /// ``` + Field, + + /// An edge from an class or struct type to an inner type member. For + /// example, the edge from `Foo` to `Foo::Bar` here: + /// + /// ```C++ + /// class Foo { + /// struct Bar { }; + /// }; + /// ``` + InnerType, + + /// An edge from an class or struct type to an inner static variable. For + /// example, the edge from `Foo` to `Foo::BAR` here: + /// + /// ```C++ + /// class Foo { + /// static const char* BAR; + /// }; + /// ``` + InnerVar, + + /// An edge from a class or struct type to one of its method functions. For + /// example, the edge from `Foo` to `Foo::bar`: + /// + /// ```C++ + /// class Foo { + /// bool bar(int x, int y); + /// }; + /// ``` + Method, + + /// An edge from a class or struct type to one of its constructor + /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: + /// + /// ```C++ + /// class Foo { + /// int my_x; + /// int my_y; + /// + /// public: + /// Foo(int x, int y); + /// }; + /// ``` + Constructor, + + /// An edge from a function declaration to its return type. For example, the + /// edge from `foo` to `int`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionReturn, + + /// An edge from a function declaration to one of its parameter types. For + /// example, the edge from `foo` to `char*`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionParameter, + + /// An edge from a static variable to its type. For example, the edge from + /// `FOO` to `const char*`: + /// + /// ```C++ + /// static const char* FOO; + /// ``` + VarType, + + /// An edge from a non-templated alias or typedef to the referenced type. + TypeReference, +} + +/// A predicate to allow visiting only sub-sets of the whole IR graph by +/// excluding certain edges from being followed by the traversal. +pub trait TraversalPredicate { + /// Should the traversal follow this edge, and visit everything that is + /// reachable through it? + fn should_follow(&self, edge: Edge) -> bool; +} + +impl TraversalPredicate for fn(Edge) -> bool { + fn should_follow(&self, edge: Edge) -> bool { + (*self)(edge) + } +} + +/// A `TraversalPredicate` implementation that follows all edges, and therefore +/// traversals using this predicate will see the whole IR graph reachable from +/// the traversal's roots. +pub fn all_edges(_: Edge) -> bool { + true +} + +/// A `TraversalPredicate` implementation that never follows any edges, and +/// therefore traversals using this predicate will only visit the traversal's +/// roots. +pub fn no_edges(_: Edge) -> bool { + false +} + +/// The storage for the set of items that have been seen (although their +/// outgoing edges might not have been fully traversed yet) in an active +/// traversal. +pub trait TraversalStorage<'ctx, 'gen> { + /// Construct a new instance of this TraversalStorage, for a new traversal. + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; + + /// Add the given item to the storage. If the item has never been seen + /// before, return `true`. Otherwise, return `false`. + /// + /// The `from` item is the item from which we discovered this item, or is + /// `None` if this item is a root. + fn add(&mut self, from: Option, item: ItemId) -> bool; +} + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { + fn new(_: &'ctx BindgenContext<'gen>) -> Self { + ItemSet::new() + } + + fn add(&mut self, _: Option, item: ItemId) -> bool { + self.insert(item) + } +} + +/// A `TraversalStorage` implementation that keeps track of how we first reached +/// each item. This is useful for providing debug assertions with meaningful +/// diagnostic messages about dangling items. +#[derive(Debug)] +pub struct Paths<'ctx, 'gen>(BTreeMap, + &'ctx BindgenContext<'gen>) + where 'gen: 'ctx; + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> + where 'gen: 'ctx, +{ + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { + Paths(BTreeMap::new(), ctx) + } + + fn add(&mut self, from: Option, item: ItemId) -> bool { + let newly_discovered = + self.0.insert(item, from.unwrap_or(item)).is_none(); + + if self.1.resolve_item_fallible(item).is_none() { + let mut path = vec![]; + let mut current = item; + loop { + let predecessor = *self.0 + .get(¤t) + .expect("We know we found this item id, so it must have a \ + predecessor"); + if predecessor == current { + break; + } + path.push(predecessor); + current = predecessor; + } + path.reverse(); + panic!("Found reference to dangling id = {:?}\nvia path = {:?}", + item, + path); + } + + newly_discovered + } +} + +/// The queue of seen-but-not-yet-traversed items. +/// +/// Using a FIFO queue with a traversal will yield a breadth-first traversal, +/// while using a LIFO queue will result in a depth-first traversal of the IR +/// graph. +pub trait TraversalQueue: Default { + /// Add a newly discovered item to the queue. + fn push(&mut self, item: ItemId); + + /// Pop the next item to traverse, if any. + fn next(&mut self) -> Option; +} + +impl TraversalQueue for Vec { + fn push(&mut self, item: ItemId) { + self.push(item); + } + + fn next(&mut self) -> Option { + self.pop() + } +} + +impl TraversalQueue for VecDeque { + fn push(&mut self, item: ItemId) { + self.push_back(item); + } + + fn next(&mut self) -> Option { + self.pop_front() + } +} + +/// Something that can receive edges from a `Trace` implementation. +pub trait Tracer { + /// Note an edge between items. Called from within a `Trace` implementation. + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); + + /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. + fn visit(&mut self, item: ItemId) { + self.visit_kind(item, EdgeKind::Generic); + } +} + +impl Tracer for F + where F: FnMut(ItemId, EdgeKind), +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + (*self)(item, kind) + } +} + +/// Trace all of the outgoing edges to other items. Implementations should call +/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` +/// for each of their outgoing edges. +pub trait Trace { + /// If a particular type needs extra information beyond what it has in + /// `self` and `context` to find its referenced items, its implementation + /// can define this associated type, forcing callers to pass the needed + /// information through. + type Extra; + + /// Trace all of this item's outgoing edges to other items. + fn trace(&self, + context: &BindgenContext, + tracer: &mut T, + extra: &Self::Extra) + where T: Tracer; +} + +/// An graph traversal of the transitive closure of references between items. +/// +/// See `BindgenContext::whitelisted_items` for more information. +pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + ctx: &'ctx BindgenContext<'gen>, + + /// The set of items we have seen thus far in this traversal. + seen: Storage, + + /// The set of items that we have seen, but have yet to traverse. + queue: Queue, + + /// The predicate that determins which edges this traversal will follow. + predicate: Predicate, + + /// The item we are currently traversing. + currently_traversing: Option, +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, + 'gen, + Storage, + Queue, + Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + /// Begin a new traversal, starting from the given roots. + pub fn new(ctx: &'ctx BindgenContext<'gen>, + roots: R, + predicate: Predicate) + -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where R: IntoIterator, + { + let mut seen = Storage::new(ctx); + let mut queue = Queue::default(); + + for id in roots { + seen.add(None, id); + queue.push(id); + } + + ItemTraversal { + ctx: ctx, + seen: seen, + queue: queue, + predicate: predicate, + currently_traversing: None, + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + let edge = Edge::new(item, kind); + if !self.predicate.should_follow(edge) { + return; + } + + let is_newly_discovered = self.seen + .add(self.currently_traversing, item); + if is_newly_discovered { + self.queue.push(item) + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + type Item = ItemId; + + fn next(&mut self) -> Option { + let id = match self.queue.next() { + None => return None, + Some(id) => id, + }; + + let newly_discovered = self.seen.add(None, id); + debug_assert!(!newly_discovered, + "should have already seen anything we get out of our queue"); + debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), + "should only get IDs of actual items in our context during traversal"); + + self.currently_traversing = Some(id); + id.trace(self.ctx, self, &()); + self.currently_traversing = None; + + Some(id) + } +} + +/// An iterator to find any dangling items. +/// +/// See `BindgenContext::assert_no_dangling_item_traversal` for more +/// information. +pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = + ItemTraversal<'ctx, + 'gen, + Paths<'ctx, 'gen>, + VecDeque, + fn(Edge) -> bool>; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(dead_code)] + fn traversal_predicate_is_object_safe() { + // This should compile only if TraversalPredicate is object safe. + fn takes_by_trait_object(_: &TraversalPredicate) {} + } +} diff --git a/src/ir/var.rs b/src/ir/var.rs index ba9bfe0ede..656a1a6dfd 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -1,342 +1,342 @@ -//! Intermediate representation of variables. - -use super::context::{BindgenContext, ItemId}; -use super::dot::DotAttributes; -use super::function::cursor_mangling; -use super::int::IntKind; -use super::item::Item; -use super::ty::{FloatKind, TypeKind}; -use cexpr; -use clang; -use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; -use std::io; -use std::num::Wrapping; - -/// The type for a constant variable. -#[derive(Debug)] -pub enum VarType { - /// A boolean. - Bool(bool), - /// An integer. - Int(i64), - /// A floating point number. - Float(f64), - /// A character. - Char(u8), - /// A string, not necessarily well-formed utf-8. - String(Vec), -} - -/// A `Var` is our intermediate representation of a variable. -#[derive(Debug)] -pub struct Var { - /// The name of the variable. - name: String, - /// The mangled name of the variable. - mangled_name: Option, - /// The type of the variable. - ty: ItemId, - /// The value of the variable, that needs to be suitable for `ty`. - val: Option, - /// Whether this variable is const. - is_const: bool, -} - -impl Var { - /// Construct a new `Var`. - pub fn new(name: String, - mangled: Option, - ty: ItemId, - val: Option, - is_const: bool) - -> Var { - assert!(!name.is_empty()); - Var { - name: name, - mangled_name: mangled, - ty: ty, - val: val, - is_const: is_const, - } - } - - /// Is this variable `const` qualified? - pub fn is_const(&self) -> bool { - self.is_const - } - - /// The value of this constant variable, if any. - pub fn val(&self) -> Option<&VarType> { - self.val.as_ref() - } - - /// Get this variable's type. - pub fn ty(&self) -> ItemId { - self.ty - } - - /// Get this variable's name. - pub fn name(&self) -> &str { - &self.name - } - - /// Get this variable's mangled name. - pub fn mangled_name(&self) -> Option<&str> { - self.mangled_name.as_ref().map(|n| &**n) - } -} - -impl DotAttributes for Var { - fn dot_attributes(&self, - _ctx: &BindgenContext, - out: &mut W) - -> io::Result<()> - where W: io::Write, - { - if self.is_const { - try!(writeln!(out, "consttrue")); - } - - if let Some(ref mangled) = self.mangled_name { - try!(writeln!(out, - "mangled name{}", - mangled)); - } - - Ok(()) - } -} - -impl ClangSubItemParser for Var { - fn parse(cursor: clang::Cursor, - ctx: &mut BindgenContext) - -> Result, ParseError> { - use clang_sys::*; - use cexpr::expr::EvalResult; - use cexpr::literal::CChar; - match cursor.kind() { - CXCursor_MacroDefinition => { - - if let Some(visitor) = ctx.parse_callbacks() { - visitor.parsed_macro(&cursor.spelling()); - } - - let value = parse_macro(ctx, &cursor, ctx.translation_unit()); - - let (id, value) = match value { - Some(v) => v, - None => return Err(ParseError::Continue), - }; - - assert!(!id.is_empty(), "Empty macro name?"); - - let previously_defined = ctx.parsed_macro(&id); - - // NB: It's important to "note" the macro even if the result is - // not an integer, otherwise we might loose other kind of - // derived macros. - ctx.note_parsed_macro(id.clone(), value.clone()); - - if previously_defined { - let name = String::from_utf8(id).unwrap(); - warn!("Duplicated macro definition: {}", name); - return Err(ParseError::Continue); - } - - // NOTE: Unwrapping, here and above, is safe, because the - // identifier of a token comes straight from clang, and we - // enforce utf8 there, so we should have already panicked at - // this point. - let name = String::from_utf8(id).unwrap(); - let (type_kind, val) = match value { - EvalResult::Invalid => return Err(ParseError::Continue), - EvalResult::Float(f) => { - (TypeKind::Float(FloatKind::Double), VarType::Float(f)) - } - EvalResult::Char(c) => { - let c = match c { - CChar::Char(c) => { - assert_eq!(c.len_utf8(), 1); - c as u8 - } - CChar::Raw(c) => { - assert!(c <= ::std::u8::MAX as u64); - c as u8 - } - }; - - (TypeKind::Int(IntKind::U8), VarType::Char(c)) - } - EvalResult::Str(val) => { - let char_ty = - Item::builtin_type(TypeKind::Int(IntKind::U8), - true, - ctx); - (TypeKind::Pointer(char_ty), VarType::String(val)) - } - EvalResult::Int(Wrapping(value)) => { - let kind = ctx.parse_callbacks() - .and_then(|c| c.int_macro(&name, value)) - .unwrap_or_else(|| if value < 0 { - if value < i32::min_value() as i64 { - IntKind::LongLong - } else { - IntKind::Int - } - } else if value > u32::max_value() as i64 { - IntKind::ULongLong - } else { - IntKind::UInt - }); - - (TypeKind::Int(kind), VarType::Int(value)) - } - }; - - let ty = Item::builtin_type(type_kind, true, ctx); - - Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), - Some(cursor))) - } - CXCursor_VarDecl => { - let name = cursor.spelling(); - if name.is_empty() { - warn!("Empty constant name?"); - return Err(ParseError::Continue); - } - - let ty = cursor.cur_type(); - - // XXX this is redundant, remove! - let is_const = ty.is_const(); - - let ty = match Item::from_ty(&ty, cursor, None, ctx) { - Ok(ty) => ty, - Err(e) => { - assert_eq!(ty.kind(), - CXType_Auto, - "Couldn't resolve constant type, and it \ - wasn't an nondeductible auto type!"); - return Err(e); - } - }; - - // Note: Ty might not be totally resolved yet, see - // tests/headers/inner_const.hpp - // - // That's fine because in that case we know it's not a literal. - let canonical_ty = ctx.safe_resolve_type(ty) - .and_then(|t| t.safe_canonical_type(ctx)); - - let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); - let is_float = canonical_ty.map_or(false, |t| t.is_float()); - - // TODO: We could handle `char` more gracefully. - // TODO: Strings, though the lookup is a bit more hard (we need - // to look at the canonical type of the pointee too, and check - // is char, u8, or i8 I guess). - let value = if is_integer { - let kind = match *canonical_ty.unwrap().kind() { - TypeKind::Int(kind) => kind, - _ => unreachable!(), - }; - - let mut val = cursor.evaluate() - .and_then(|v| v.as_int()) - .map(|val| val as i64); - if val.is_none() || !kind.signedness_matches(val.unwrap()) { - let tu = ctx.translation_unit(); - val = get_integer_literal_from_cursor(&cursor, tu); - } - - val.map(|val| if kind == IntKind::Bool { - VarType::Bool(val != 0) - } else { - VarType::Int(val) - }) - } else if is_float { - cursor.evaluate() - .and_then(|v| v.as_double()) - .map(VarType::Float) - } else { - cursor.evaluate() - .and_then(|v| v.as_literal_string()) - .map(VarType::String) - }; - - let mangling = cursor_mangling(ctx, &cursor); - let var = Var::new(name, mangling, ty, value, is_const); - - Ok(ParseResult::New(var, Some(cursor))) - } - _ => { - /* TODO */ - Err(ParseError::Continue) - } - } - } -} - -/// Try and parse a macro using all the macros parsed until now. -fn parse_macro(ctx: &BindgenContext, - cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option<(Vec, cexpr::expr::EvalResult)> { - use cexpr::{expr, nom}; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - let parser = expr::IdentifierParser::new(ctx.parsed_macros()); - let result = parser.macro_definition(&cexpr_tokens); - - match result { - nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), - _ => None, - } -} - -fn parse_int_literal_tokens(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use cexpr::{expr, nom}; - use cexpr::expr::EvalResult; - - let cexpr_tokens = match unit.cexpr_tokens(cursor) { - None => return None, - Some(tokens) => tokens, - }; - - // TODO(emilio): We can try to parse other kinds of literals. - match expr::expr(&cexpr_tokens) { - nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), - _ => None, - } -} - -fn get_integer_literal_from_cursor(cursor: &clang::Cursor, - unit: &clang::TranslationUnit) - -> Option { - use clang_sys::*; - let mut value = None; - cursor.visit(|c| { - match c.kind() { - CXCursor_IntegerLiteral | - CXCursor_UnaryOperator => { - value = parse_int_literal_tokens(&c, unit); - } - CXCursor_UnexposedExpr => { - value = get_integer_literal_from_cursor(&c, unit); - } - _ => (), - } - if value.is_some() { - CXChildVisit_Break - } else { - CXChildVisit_Continue - } - }); - value -} +//! Intermediate representation of variables. + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use super::function::cursor_mangling; +use super::int::IntKind; +use super::item::Item; +use super::ty::{FloatKind, TypeKind}; +use cexpr; +use clang; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; +use std::num::Wrapping; + +/// The type for a constant variable. +#[derive(Debug)] +pub enum VarType { + /// A boolean. + Bool(bool), + /// An integer. + Int(i64), + /// A floating point number. + Float(f64), + /// A character. + Char(u8), + /// A string, not necessarily well-formed utf-8. + String(Vec), +} + +/// A `Var` is our intermediate representation of a variable. +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option, + /// The type of the variable. + ty: ItemId, + /// The value of the variable, that needs to be suitable for `ty`. + val: Option, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + /// Construct a new `Var`. + pub fn new(name: String, + mangled: Option, + ty: ItemId, + val: Option, + is_const: bool) + -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + /// Is this variable `const` qualified? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// The value of this constant variable, if any. + pub fn val(&self) -> Option<&VarType> { + self.val.as_ref() + } + + /// Get this variable's type. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get this variable's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variable's mangled name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl DotAttributes for Var { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + if self.is_const { + try!(writeln!(out, "consttrue")); + } + + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, + "mangled name{}", + mangled)); + } + + Ok(()) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + use cexpr::expr::EvalResult; + use cexpr::literal::CChar; + match cursor.kind() { + CXCursor_MacroDefinition => { + + if let Some(visitor) = ctx.parse_callbacks() { + visitor.parsed_macro(&cursor.spelling()); + } + + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); + + let (id, value) = match value { + Some(v) => v, + None => return Err(ParseError::Continue), + }; + + assert!(!id.is_empty(), "Empty macro name?"); + + let previously_defined = ctx.parsed_macro(&id); + + // NB: It's important to "note" the macro even if the result is + // not an integer, otherwise we might loose other kind of + // derived macros. + ctx.note_parsed_macro(id.clone(), value.clone()); + + if previously_defined { + let name = String::from_utf8(id).unwrap(); + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + + // NOTE: Unwrapping, here and above, is safe, because the + // identifier of a token comes straight from clang, and we + // enforce utf8 there, so we should have already panicked at + // this point. + let name = String::from_utf8(id).unwrap(); + let (type_kind, val) = match value { + EvalResult::Invalid => return Err(ParseError::Continue), + EvalResult::Float(f) => { + (TypeKind::Float(FloatKind::Double), VarType::Float(f)) + } + EvalResult::Char(c) => { + let c = match c { + CChar::Char(c) => { + assert_eq!(c.len_utf8(), 1); + c as u8 + } + CChar::Raw(c) => { + assert!(c <= ::std::u8::MAX as u64); + c as u8 + } + }; + + (TypeKind::Int(IntKind::U8), VarType::Char(c)) + } + EvalResult::Str(val) => { + let char_ty = + Item::builtin_type(TypeKind::Int(IntKind::U8), + true, + ctx); + (TypeKind::Pointer(char_ty), VarType::String(val)) + } + EvalResult::Int(Wrapping(value)) => { + let kind = ctx.parse_callbacks() + .and_then(|c| c.int_macro(&name, value)) + .unwrap_or_else(|| if value < 0 { + if value < i32::min_value() as i64 { + IntKind::LongLong + } else { + IntKind::Int + } + } else if value > u32::max_value() as i64 { + IntKind::ULongLong + } else { + IntKind::UInt + }); + + (TypeKind::Int(kind), VarType::Int(value)) + } + }; + + let ty = Item::builtin_type(type_kind, true, ctx); + + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), + Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = match Item::from_ty(&ty, cursor, None, ctx) { + Ok(ty) => ty, + Err(e) => { + assert_eq!(ty.kind(), + CXType_Auto, + "Couldn't resolve constant type, and it \ + wasn't an nondeductible auto type!"); + return Err(e); + } + }; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + let canonical_ty = ctx.safe_resolve_type(ty) + .and_then(|t| t.safe_canonical_type(ctx)); + + let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); + let is_float = canonical_ty.map_or(false, |t| t.is_float()); + + // TODO: We could handle `char` more gracefully. + // TODO: Strings, though the lookup is a bit more hard (we need + // to look at the canonical type of the pointee too, and check + // is char, u8, or i8 I guess). + let value = if is_integer { + let kind = match *canonical_ty.unwrap().kind() { + TypeKind::Int(kind) => kind, + _ => unreachable!(), + }; + + let mut val = cursor.evaluate() + .and_then(|v| v.as_int()) + .map(|val| val as i64); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { + let tu = ctx.translation_unit(); + val = get_integer_literal_from_cursor(&cursor, tu); + } + + val.map(|val| if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + }) + } else if is_float { + cursor.evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float) + } else { + cursor.evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String) + }; + + let mangling = cursor_mangling(ctx, &cursor); + let var = Var::new(name, mangling, ty, value, is_const); + + Ok(ParseResult::New(var, Some(cursor))) + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +/// Try and parse a macro using all the macros parsed until now. +fn parse_macro(ctx: &BindgenContext, + cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<(Vec, cexpr::expr::EvalResult)> { + use cexpr::{expr, nom}; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); + let result = parser.macro_definition(&cexpr_tokens); + + match result { + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), + _ => None, + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use cexpr::{expr, nom}; + use cexpr::expr::EvalResult; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + // TODO(emilio): We can try to parse other kinds of literals. + match expr::expr(&cexpr_tokens) { + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), + _ => None, + } +} + +fn get_integer_literal_from_cursor(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use clang_sys::*; + let mut value = None; + cursor.visit(|c| { + match c.kind() { + CXCursor_IntegerLiteral | + CXCursor_UnaryOperator => { + value = parse_int_literal_tokens(&c, unit); + } + CXCursor_UnexposedExpr => { + value = get_integer_literal_from_cursor(&c, unit); + } + _ => (), + } + if value.is_some() { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + value +} From d4197b673962e7fa2f9a4f43e85d7a7d578096f5 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 17:47:38 -0400 Subject: [PATCH 11/18] more cleanup --- .gitignore | 15 +- src/clang.rs | 3516 ++++++++++++++++++++++++------------------------ src/main.rs | 22 +- src/options.rs | 2 +- 4 files changed, 1776 insertions(+), 1779 deletions(-) diff --git a/.gitignore b/.gitignore index 15430b5261..71a7df6d78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ -# Cargo -target/ -*~ -bindgen-integration/Cargo.lock -tests/expectations/Cargo.lock -#*# -bindgen-integration/mybuild.rs -ir.dot -ir.png +# Cargo +target/ +*~ +bindgen-integration/Cargo.lock +tests/expectations/Cargo.lock +#*# diff --git a/src/clang.rs b/src/clang.rs index e4703c4941..b4acf2046f 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -1,1758 +1,1758 @@ -//! A higher level Clang API built on top of the generated bindings in the -//! `clang_sys` module. - -#![allow(non_upper_case_globals, dead_code)] - - -use cexpr; -use clang_sys::*; -use regex; -use std::{mem, ptr, slice}; -use std::ffi::{CStr, CString}; -use std::fmt; -use std::hash::Hash; -use std::hash::Hasher; -use std::os::raw::{c_char, c_int, c_uint, c_ulong}; - -/// A cursor into the Clang AST, pointing to an AST node. -/// -/// We call the AST node pointed to by the cursor the cursor's "referent". -#[derive(Copy, Clone)] -pub struct Cursor { - x: CXCursor, -} - -impl fmt::Debug for Cursor { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "Cursor({} kind: {}, loc: {}, usr: {:?})", - self.spelling(), - kind_to_str(self.kind()), - self.location(), - self.usr()) - } -} - -impl Cursor { - /// Get the Unified Symbol Resolution for this cursor's referent, if - /// available. - /// - /// The USR can be used to compare entities across translation units. - pub fn usr(&self) -> Option { - let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; - if s.is_empty() { None } else { Some(s) } - } - - /// Is this cursor's referent a declaration? - pub fn is_declaration(&self) -> bool { - unsafe { clang_isDeclaration(self.kind()) != 0 } - } - - /// Get the null cursor, which has no referent. - pub fn null() -> Self { - Cursor { - x: unsafe { clang_getNullCursor() }, - } - } - - /// Get this cursor's referent's spelling. - pub fn spelling(&self) -> String { - unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } - } - - /// Get this cursor's referent's display name. - /// - /// This is not necessarily a valid identifier. It includes extra - /// information, such as parameters for a function, etc. - pub fn display_name(&self) -> String { - unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } - } - - /// Get the mangled name of this cursor's referent. - pub fn mangling(&self) -> String { - if clang_Cursor_getMangling::is_loaded() { - unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } - } else { - self.spelling() - } - } - - /// Returns whether the cursor refers to a built-in definition. - pub fn is_builtin(&self) -> bool { - let (file, _, _, _) = self.location().location(); - file.name().is_none() - } - - /// Get the `Cursor` for this cursor's referent's lexical parent. - /// - /// The lexical parent is the parent of the definition. The semantic parent - /// is the parent of the declaration. Generally, the lexical parent doesn't - /// have any effect on semantics, while the semantic parent does. - /// - /// In the following snippet, the `Foo` class would be the semantic parent - /// of the out-of-line `method` definition, while the lexical parent is the - /// translation unit. - /// - /// ```c++ - /// class Foo { - /// void method(); - /// }; - /// - /// void Foo::method() { /* ... */ } - /// ``` - pub fn lexical_parent(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getCursorLexicalParent(self.x), - } - } - } - - /// Get the referent's semantic parent, if one is available. - /// - /// See documentation for `lexical_parent` for details on semantic vs - /// lexical parents. - pub fn fallible_semantic_parent(&self) -> Option { - let sp = unsafe { - Cursor { - x: clang_getCursorSemanticParent(self.x), - } - }; - if sp == *self || !sp.is_valid() { - return None; - } - Some(sp) - } - - /// Get the referent's semantic parent. - /// - /// See documentation for `lexical_parent` for details on semantic vs - /// lexical parents. - pub fn semantic_parent(&self) -> Cursor { - self.fallible_semantic_parent().unwrap() - } - - /// Return the number of template arguments used by this cursor's referent, - /// if the referent is either a template instantiation. Returns `None` - /// otherwise. - /// - /// NOTE: This may not return `Some` for partial template specializations, - /// see #193 and #194. - pub fn num_template_args(&self) -> Option { - // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while - // `clang_Cursor_getNumTemplateArguments` is totally unreliable. - // Therefore, try former first, and only fallback to the latter if we - // have to. - self.cur_type() - .num_template_args() - .or_else(|| { - let n: c_int = - unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; - - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None - } - }) - .or_else(|| { - let canonical = self.canonical(); - if canonical != *self { - canonical.num_template_args() - } else { - None - } - }) - } - - /// Get a cursor pointing to this referent's containing translation unit. - /// - /// Note that we shouldn't create a `TranslationUnit` struct here, because - /// bindgen assumes there will only be one of them alive at a time, and - /// disposes it on drop. That can change if this would be required, but I - /// think we can survive fine without it. - pub fn translation_unit(&self) -> Cursor { - assert!(self.is_valid()); - unsafe { - let tu = clang_Cursor_getTranslationUnit(self.x); - let cursor = Cursor { - x: clang_getTranslationUnitCursor(tu), - }; - assert!(cursor.is_valid()); - cursor - } - } - - /// Is the referent a top level construct? - pub fn is_toplevel(&self) -> bool { - let mut semantic_parent = self.fallible_semantic_parent(); - - while semantic_parent.is_some() && - (semantic_parent.unwrap().kind() == CXCursor_Namespace || - semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || - semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { - semantic_parent = semantic_parent.unwrap() - .fallible_semantic_parent(); - } - - let tu = self.translation_unit(); - // Yes, this can happen with, e.g., macro definitions. - semantic_parent == tu.fallible_semantic_parent() - } - - /// There are a few kinds of types that we need to treat specially, mainly - /// not tracking the type declaration but the location of the cursor, given - /// clang doesn't expose a proper declaration for these types. - pub fn is_template_like(&self) -> bool { - match self.kind() { - CXCursor_ClassTemplate | - CXCursor_ClassTemplatePartialSpecialization | - CXCursor_TypeAliasTemplateDecl => true, - _ => false, - } - } - - /// Get the kind of referent this cursor is pointing to. - pub fn kind(&self) -> CXCursorKind { - self.x.kind - } - - /// Returns true is the cursor is a definition - pub fn is_definition(&self) -> bool { - unsafe { clang_isCursorDefinition(self.x) != 0 } - } - - /// Is the referent a template specialization? - pub fn is_template_specialization(&self) -> bool { - self.specialized().is_some() - } - - /// Is the referent a fully specialized template specialization without any - /// remaining free template arguments? - pub fn is_fully_specialized_template(&self) -> bool { - self.is_template_specialization() && - self.kind() != CXCursor_ClassTemplatePartialSpecialization && - self.num_template_args().unwrap_or(0) > 0 - } - - /// Is the referent a template specialization that still has remaining free - /// template arguments? - pub fn is_in_non_fully_specialized_template(&self) -> bool { - if self.is_toplevel() { - return false; - } - - let parent = self.semantic_parent(); - if parent.is_fully_specialized_template() { - return false; - } - - if !parent.is_template_like() { - return parent.is_in_non_fully_specialized_template(); - } - - return true; - } - - /// Is this cursor pointing a valid referent? - pub fn is_valid(&self) -> bool { - unsafe { clang_isInvalid(self.kind()) == 0 } - } - - /// Get the source location for the referent. - pub fn location(&self) -> SourceLocation { - unsafe { - SourceLocation { - x: clang_getCursorLocation(self.x), - } - } - } - - /// Get the source location range for the referent. - pub fn extent(&self) -> CXSourceRange { - unsafe { clang_getCursorExtent(self.x) } - } - - /// Get the raw declaration comment for this referent, if one exists. - pub fn raw_comment(&self) -> Option { - let s = unsafe { - cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) - }; - if s.is_empty() { None } else { Some(s) } - } - - /// Get the referent's parsed comment. - pub fn comment(&self) -> Comment { - unsafe { - Comment { - x: clang_Cursor_getParsedComment(self.x), - } - } - } - - /// Get the referent's type. - pub fn cur_type(&self) -> Type { - unsafe { - Type { - x: clang_getCursorType(self.x), - } - } - } - - /// Given that this cursor's referent is a reference to another type, or is - /// a declaration, get the cursor pointing to the referenced type or type of - /// the declared thing. - pub fn definition(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getCursorDefinition(self.x), - }; - - if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound { - Some(ret) - } else { - None - } - } - } - - /// Given that this cursor's referent is reference type, get the cursor - /// pointing to the referenced type. - pub fn referenced(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getCursorReferenced(self.x), - }; - - if ret.is_valid() { Some(ret) } else { None } - } - } - - /// Get the canonical cursor for this referent. - /// - /// Many types can be declared multiple times before finally being properly - /// defined. This method allows us to get the canonical cursor for the - /// referent type. - pub fn canonical(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getCanonicalCursor(self.x), - } - } - } - - /// Given that this cursor points to either a template specialization or a - /// template instantiation, get a cursor pointing to the template definition - /// that is being specialized. - pub fn specialized(&self) -> Option { - unsafe { - let ret = Cursor { - x: clang_getSpecializedCursorTemplate(self.x), - }; - if ret.is_valid() { Some(ret) } else { None } - } - } - - /// Assuming that this cursor's referent is a template declaration, get the - /// kind of cursor that would be generated for its specializations. - pub fn template_kind(&self) -> CXCursorKind { - unsafe { clang_getTemplateCursorKind(self.x) } - } - - /// Traverse this cursor's referent and its children. - /// - /// Call the given function on each AST node traversed. - pub fn visit(&self, mut visitor: Visitor) - where Visitor: FnMut(Cursor) -> CXChildVisitResult, - { - unsafe { - clang_visitChildren(self.x, - visit_children::, - mem::transmute(&mut visitor)); - } - } - - /// Collect all of this cursor's children into a vec and return them. - pub fn collect_children(&self) -> Vec { - let mut children = vec![]; - self.visit(|c| { - children.push(c); - CXChildVisit_Continue - }); - children - } - - /// Does this cursor have any children? - pub fn has_children(&self) -> bool { - let mut has_children = false; - self.visit(|_| { - has_children = true; - CXChildVisit_Break - }); - has_children - } - - /// Does this cursor have at least `n` children? - pub fn has_at_least_num_children(&self, n: usize) -> bool { - assert!(n > 0); - let mut num_left = n; - self.visit(|_| { - num_left -= 1; - if num_left == 0 { - CXChildVisit_Break - } else { - CXChildVisit_Continue - } - }); - num_left == 0 - } - - /// Returns whether the given location contains a cursor with the given - /// kind in the first level of nesting underneath (doesn't look - /// recursively). - pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { - let mut found = false; - - self.visit(|c| if c.kind() == kind { - found = true; - CXChildVisit_Break - } else { - CXChildVisit_Continue - }); - - found - } - - /// Is the referent an inlined function? - pub fn is_inlined_function(&self) -> bool { - clang_Cursor_isFunctionInlined::is_loaded() && - unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } - } - - /// Get the width of this cursor's referent bit field, or `None` if the - /// referent is not a bit field. - pub fn bit_width(&self) -> Option { - unsafe { - let w = clang_getFieldDeclBitWidth(self.x); - if w == -1 { None } else { Some(w as u32) } - } - } - - /// Get the integer representation type used to hold this cursor's referent - /// enum type. - pub fn enum_type(&self) -> Option { - unsafe { - let t = Type { - x: clang_getEnumDeclIntegerType(self.x), - }; - if t.is_valid() { Some(t) } else { None } - } - } - - /// Get the signed constant value for this cursor's enum variant referent. - /// - /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_signed(&self) -> Option { - unsafe { - if self.kind() == CXCursor_EnumConstantDecl { - Some(clang_getEnumConstantDeclValue(self.x) as i64) - } else { - None - } - } - } - - /// Get the unsigned constant value for this cursor's enum variant referent. - /// - /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_unsigned(&self) -> Option { - unsafe { - if self.kind() == CXCursor_EnumConstantDecl { - Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) - } else { - None - } - } - } - - /// Given that this cursor's referent is a `typedef`, get the `Type` that is - /// being aliased. - pub fn typedef_type(&self) -> Option { - let inner = Type { - x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, - }; - - if inner.is_valid() { Some(inner) } else { None } - } - - /// Get the linkage kind for this cursor's referent. - /// - /// This only applies to functions and variables. - pub fn linkage(&self) -> CXLinkageKind { - unsafe { clang_getCursorLinkage(self.x) } - } - - /// Get the visibility of this cursor's referent. - pub fn visibility(&self) -> CXVisibilityKind { - if clang_getCursorVisibility::is_loaded() { - unsafe { clang_getCursorVisibility(self.x) } - } else { - CXVisibility_Default - } - } - - /// Given that this cursor's referent is a function, return cursors to its - /// parameters. - pub fn args(&self) -> Option> { - // XXX: We might want to use and keep num_args - // match self.kind() { - // CXCursor_FunctionDecl | - // CXCursor_CXXMethod => { - unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { - None - } else { - let num = w as u32; - - let mut args = vec![]; - for i in 0..num { - args.push(Cursor { - x: clang_Cursor_getArgument(self.x, i as c_uint), - }); - } - Some(args) - } - } - } - - /// Given that this cursor's referent is a function/method call or - /// declaration, return the number of arguments it takes. - /// - /// Returns -1 if the cursor's referent is not a function/method call or - /// declaration. - pub fn num_args(&self) -> Result { - unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { Err(()) } else { Ok(w as u32) } - } - } - - /// Get the access specifier for this cursor's referent. - pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { - unsafe { clang_getCXXAccessSpecifier(self.x) } - } - - /// Is this cursor's referent a field declaration that is marked as - /// `mutable`? - pub fn is_mutable_field(&self) -> bool { - clang_CXXField_isMutable::is_loaded() && - unsafe { clang_CXXField_isMutable(self.x) != 0 } - } - - /// Get the offset of the field represented by the Cursor. - pub fn offset_of_field(&self) -> Result { - if !clang_Cursor_getOffsetOfField::is_loaded() { - return Err(LayoutError::from(-1)); - } - - let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; - - if offset < 0 { - Err(LayoutError::from(offset as i32)) - } else { - Ok(offset as usize) - } - } - - /// Is this cursor's referent a member function that is declared `static`? - pub fn method_is_static(&self) -> bool { - unsafe { clang_CXXMethod_isStatic(self.x) != 0 } - } - - /// Is this cursor's referent a member function that is declared `const`? - pub fn method_is_const(&self) -> bool { - unsafe { clang_CXXMethod_isConst(self.x) != 0 } - } - - /// Is this cursor's referent a member function that is declared `const`? - pub fn method_is_virtual(&self) -> bool { - unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } - } - - /// Is this cursor's referent a struct or class with virtual members? - pub fn is_virtual_base(&self) -> bool { - unsafe { clang_isVirtualBase(self.x) != 0 } - } - - /// Try to evaluate this cursor. - pub fn evaluate(&self) -> Option { - EvalResult::new(*self) - } - - /// Return the result type for this cursor - pub fn ret_type(&self) -> Option { - let rt = Type { - x: unsafe { clang_getCursorResultType(self.x) }, - }; - if rt.is_valid() { Some(rt) } else { None } - } -} - -/// Checks whether the name looks like an identifier, i.e. is alphanumeric -/// (including '_') and does not start with a digit. -pub fn is_valid_identifier(name: &str) -> bool { - let mut chars = name.chars(); - let first_valid = chars.next() - .map(|c| c.is_alphabetic() || c == '_') - .unwrap_or(false); - - first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') -} - -extern "C" fn visit_children(cur: CXCursor, - _parent: CXCursor, - data: CXClientData) - -> CXChildVisitResult - where Visitor: FnMut(Cursor) -> CXChildVisitResult, -{ - let func: &mut Visitor = unsafe { mem::transmute(data) }; - let child = Cursor { - x: cur, - }; - - (*func)(child) -} - -impl PartialEq for Cursor { - fn eq(&self, other: &Cursor) -> bool { - unsafe { clang_equalCursors(self.x, other.x) == 1 } - } -} - -impl Eq for Cursor {} - -impl Hash for Cursor { - fn hash(&self, state: &mut H) { - unsafe { clang_hashCursor(self.x) }.hash(state) - } -} - -/// The type of a node in clang's AST. -#[derive(Clone, Copy)] -pub struct Type { - x: CXType, -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - unsafe { clang_equalTypes(self.x, other.x) != 0 } - } -} - -impl Eq for Type {} - -impl fmt::Debug for Type { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})", - self.spelling(), - type_to_str(self.kind()), - self.call_conv(), - self.declaration(), - self.declaration().canonical()) - } -} - -/// An error about the layout of a struct, class, or type. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum LayoutError { - /// Asked for the layout of an invalid type. - Invalid, - /// Asked for the layout of an incomplete type. - Incomplete, - /// Asked for the layout of a dependent type. - Dependent, - /// Asked for the layout of a type that does not have constant size. - NotConstantSize, - /// Asked for the layout of a field in a type that does not have such a - /// field. - InvalidFieldName, - /// An unknown layout error. - Unknown, -} - -impl ::std::convert::From for LayoutError { - fn from(val: i32) -> Self { - use self::LayoutError::*; - - match val { - CXTypeLayoutError_Invalid => Invalid, - CXTypeLayoutError_Incomplete => Incomplete, - CXTypeLayoutError_Dependent => Dependent, - CXTypeLayoutError_NotConstantSize => NotConstantSize, - CXTypeLayoutError_InvalidFieldName => InvalidFieldName, - _ => Unknown, - } - } -} - -impl Type { - /// Get this type's kind. - pub fn kind(&self) -> CXTypeKind { - self.x.kind - } - - /// Get a cursor pointing to this type's declaration. - pub fn declaration(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTypeDeclaration(self.x), - } - } - } - - /// Get the canonical declaration of this type, if it is available. - pub fn canonical_declaration(&self, - location: Option<&Cursor>) - -> Option { - let mut declaration = self.declaration(); - if !declaration.is_valid() { - if let Some(location) = location { - let mut location = *location; - if let Some(referenced) = location.referenced() { - location = referenced; - } - if location.is_template_like() { - declaration = location; - } - } - } - - let canonical = declaration.canonical(); - if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound { - Some(CanonicalTypeDeclaration(*self, canonical)) - } else { - None - } - } - - /// Get a raw display name for this type. - pub fn spelling(&self) -> String { - let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; - // Clang 5.0 introduced changes in the spelling API so it returned the - // full qualified name. Let's undo that here. - if s.split("::").all(|s| is_valid_identifier(s)) { - if let Some(s) = s.split("::").last() { - return s.to_owned(); - } - } - - s - } - - /// Is this type const qualified? - pub fn is_const(&self) -> bool { - unsafe { clang_isConstQualifiedType(self.x) != 0 } - } - - /// What is the size of this type? Paper over invalid types by returning `0` - /// for them. - pub fn size(&self) -> usize { - unsafe { - let val = clang_Type_getSizeOf(self.x); - if val < 0 { 0 } else { val as usize } - } - } - - /// What is the size of this type? - pub fn fallible_size(&self) -> Result { - let val = unsafe { clang_Type_getSizeOf(self.x) }; - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) - } - } - - /// What is the alignment of this type? Paper over invalid types by - /// returning `0`. - pub fn align(&self) -> usize { - unsafe { - let val = clang_Type_getAlignOf(self.x); - if val < 0 { 0 } else { val as usize } - } - } - - /// What is the alignment of this type? - pub fn fallible_align(&self) -> Result { - unsafe { - let val = clang_Type_getAlignOf(self.x); - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) - } - } - } - - /// Get the layout for this type, or an error describing why it does not - /// have a valid layout. - pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { - use ir::layout::Layout; - let size = try!(self.fallible_size()); - let align = try!(self.fallible_align()); - Ok(Layout::new(size, align)) - } - - /// Get the number of template arguments this type has, or `None` if it is - /// not some kind of template. - pub fn num_template_args(&self) -> Option { - let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None - } - } - - /// If this type is a class template specialization, return its - /// template arguments. Otherwise, return None. - pub fn template_args(&self) -> Option { - self.num_template_args().map(|n| { - TypeTemplateArgIterator { - x: self.x, - length: n, - index: 0, - } - }) - } - - /// Given that this type is a pointer type, return the type that it points - /// to. - pub fn pointee_type(&self) -> Option { - match self.kind() { - CXType_Pointer | - CXType_RValueReference | - CXType_LValueReference | - CXType_MemberPointer | - CXType_ObjCObjectPointer => { - let ret = Type { - x: unsafe { clang_getPointeeType(self.x) }, - }; - debug_assert!(ret.is_valid()); - Some(ret) - } - _ => None, - } - } - - /// Given that this type is an array, vector, or complex type, return the - /// type of its elements. - pub fn elem_type(&self) -> Option { - let current_type = Type { - x: unsafe { clang_getElementType(self.x) }, - }; - if current_type.is_valid() { - Some(current_type) - } else { - None - } - } - - /// Given that this type is an array or vector type, return its number of - /// elements. - pub fn num_elements(&self) -> Option { - let num_elements_returned = unsafe { clang_getNumElements(self.x) }; - if num_elements_returned != -1 { - Some(num_elements_returned as usize) - } else { - None - } - } - - /// Get the canonical version of this type. This sees through `typdef`s and - /// aliases to get the underlying, canonical type. - pub fn canonical_type(&self) -> Type { - unsafe { - Type { - x: clang_getCanonicalType(self.x), - } - } - } - - /// Is this type a variadic function type? - pub fn is_variadic(&self) -> bool { - unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } - } - - /// Given that this type is a function type, get the type of its return - /// value. - pub fn ret_type(&self) -> Option { - let rt = Type { - x: unsafe { clang_getResultType(self.x) }, - }; - if rt.is_valid() { Some(rt) } else { None } - } - - /// Given that this type is a function type, get its calling convention. If - /// this is not a function type, `CXCallingConv_Invalid` is returned. - pub fn call_conv(&self) -> CXCallingConv { - unsafe { clang_getFunctionTypeCallingConv(self.x) } - } - - /// For elaborated types (types which use `class`, `struct`, or `union` to - /// disambiguate types from local bindings), get the underlying type. - pub fn named(&self) -> Type { - unsafe { - Type { - x: if clang_Type_getNamedType::is_loaded() { - clang_Type_getNamedType(self.x) - } else { - self.x - }, - } - } - } - - /// Is this a valid type? - pub fn is_valid(&self) -> bool { - self.kind() != CXType_Invalid - } - - /// Is this a valid and exposed type? - pub fn is_valid_and_exposed(&self) -> bool { - self.is_valid() && self.kind() != CXType_Unexposed - } - - /// Is this type a fully instantiated template? - pub fn is_fully_instantiated_template(&self) -> bool { - // Yep, the spelling of this containing type-parameter is extremely - // nasty... But can happen in . Unfortunately I couldn't - // reduce it enough :( - self.template_args().map_or(false, |args| args.len() > 0) && - match self.declaration().kind() { - CXCursor_ClassTemplatePartialSpecialization | - CXCursor_TypeAliasTemplateDecl | - CXCursor_TemplateTemplateParameter => false, - _ => true, - } - } - - /// Is this type an associated template type? Eg `T::Associated` in - /// this example: - /// - /// ```c++ - /// template - /// class Foo { - /// typename T::Associated member; - /// }; - /// ``` - pub fn is_associated_type(&self) -> bool { - // This is terrible :( - fn hacky_parse_associated_type>(spelling: S) -> bool { - lazy_static! { - static ref ASSOC_TYPE_RE: regex::Regex = - regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap(); - } - ASSOC_TYPE_RE.is_match(spelling.as_ref()) - } - - self.kind() == CXType_Unexposed && - (hacky_parse_associated_type(self.spelling()) || - hacky_parse_associated_type(self.canonical_type().spelling())) - } -} - -/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its -/// cursor is the canonical declaration for its type. If you have a -/// `CanonicalTypeDeclaration` instance, you know for sure that the type and -/// cursor match up in a canonical declaration relationship, and it simply -/// cannot be otherwise. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CanonicalTypeDeclaration(Type, Cursor); - -impl CanonicalTypeDeclaration { - /// Get the type. - pub fn ty(&self) -> &Type { - &self.0 - } - - /// Get the type's canonical declaration cursor. - pub fn cursor(&self) -> &Cursor { - &self.1 - } -} - -/// An iterator for a type's template arguments. -pub struct TypeTemplateArgIterator { - x: CXType, - length: u32, - index: u32, -} - -impl Iterator for TypeTemplateArgIterator { - type Item = Type; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index as c_uint; - self.index += 1; - Some(Type { - x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, - }) - } else { - None - } - } -} - -impl ExactSizeIterator for TypeTemplateArgIterator { - fn len(&self) -> usize { - assert!(self.index <= self.length); - (self.length - self.index) as usize - } -} - -/// A `SourceLocation` is a file, line, column, and byte offset location for -/// some source text. -pub struct SourceLocation { - x: CXSourceLocation, -} - -impl SourceLocation { - /// Get the (file, line, column, byte offset) tuple for this source - /// location. - pub fn location(&self) -> (File, usize, usize, usize) { - unsafe { - let mut file = mem::zeroed(); - let mut line = 0; - let mut col = 0; - let mut off = 0; - clang_getSpellingLocation(self.x, - &mut file, - &mut line, - &mut col, - &mut off); - (File { - x: file, - }, - line as usize, - col as usize, - off as usize) - } - } -} - -impl fmt::Display for SourceLocation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (file, line, col, _) = self.location(); - if let Some(name) = file.name() { - write!(f, "{}:{}:{}", name, line, col) - } else { - "builtin definitions".fmt(f) - } - } -} - -/// A comment in the source text. -/// -/// Comments are sort of parsed by Clang, and have a tree structure. -pub struct Comment { - x: CXComment, -} - -impl Comment { - /// What kind of comment is this? - pub fn kind(&self) -> CXCommentKind { - unsafe { clang_Comment_getKind(self.x) } - } - - /// Get this comment's children comment - pub fn get_children(&self) -> CommentChildrenIterator { - CommentChildrenIterator { - parent: self.x, - length: unsafe { clang_Comment_getNumChildren(self.x) }, - index: 0, - } - } - - /// Given that this comment is the start or end of an HTML tag, get its tag - /// name. - pub fn get_tag_name(&self) -> String { - unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } - } - - /// Given that this comment is an HTML start tag, get its attributes. - pub fn get_tag_attrs(&self) -> CommentAttributesIterator { - CommentAttributesIterator { - x: self.x, - length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, - index: 0, - } - } -} - -/// An iterator for a comment's children -pub struct CommentChildrenIterator { - parent: CXComment, - length: c_uint, - index: c_uint, -} - -impl Iterator for CommentChildrenIterator { - type Item = Comment; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(Comment { - x: unsafe { clang_Comment_getChild(self.parent, idx) }, - }) - } else { - None - } - } -} - -/// An HTML start tag comment attribute -pub struct CommentAttribute { - /// HTML start tag attribute name - pub name: String, - /// HTML start tag attribute value - pub value: String, -} - -/// An iterator for a comment's attributes -pub struct CommentAttributesIterator { - x: CXComment, - length: c_uint, - index: c_uint, -} - -impl Iterator for CommentAttributesIterator { - type Item = CommentAttribute; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(CommentAttribute { - name: unsafe { - cxstring_into_string( - clang_HTMLStartTag_getAttrName(self.x, idx)) - }, - value: unsafe { - cxstring_into_string( - clang_HTMLStartTag_getAttrValue(self.x, idx)) - }, - }) - } else { - None - } - } -} - -/// A source file. -pub struct File { - x: CXFile, -} - -impl File { - /// Get the name of this source file. - pub fn name(&self) -> Option { - if self.x.is_null() { - return None; - } - Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) - } -} - -fn cxstring_into_string(s: CXString) -> String { - if s.data.is_null() { - return "".to_owned(); - } - unsafe { - let c_str = CStr::from_ptr(clang_getCString(s) as *const _); - let ret = c_str.to_string_lossy().into_owned(); - clang_disposeString(s); - ret - } -} - -/// An `Index` is an environment for a set of translation units that will -/// typically end up linked together in one final binary. -pub struct Index { - x: CXIndex, -} - -impl Index { - /// Construct a new `Index`. - /// - /// The `pch` parameter controls whether declarations in pre-compiled - /// headers are included when enumerating a translation unit's "locals". - /// - /// The `diag` parameter controls whether debugging diagnostics are enabled. - pub fn new(pch: bool, diag: bool) -> Index { - unsafe { - Index { - x: clang_createIndex(pch as c_int, diag as c_int), - } - } - } -} - -impl fmt::Debug for Index { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Index {{ }}") - } -} - -impl Drop for Index { - fn drop(&mut self) { - unsafe { - clang_disposeIndex(self.x); - } - } -} - -/// A token emitted by clang's lexer. -#[derive(Debug)] -pub struct Token { - /// The kind of token this is. - pub kind: CXTokenKind, - /// A display name for this token. - pub spelling: String, -} - -/// A translation unit (or "compilation unit"). -pub struct TranslationUnit { - x: CXTranslationUnit, -} - -impl fmt::Debug for TranslationUnit { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "TranslationUnit {{ }}") - } -} - -impl TranslationUnit { - /// Parse a source file into a translation unit. - pub fn parse(ix: &Index, - file: &str, - cmd_args: &[String], - unsaved: &[UnsavedFile], - opts: CXTranslationUnit_Flags) - -> Option { - let fname = CString::new(file).unwrap(); - let _c_args: Vec = - cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect(); - let c_args: Vec<*const c_char> = - _c_args.iter().map(|s| s.as_ptr()).collect(); - let mut c_unsaved: Vec = - unsaved.iter().map(|f| f.x).collect(); - let tu = unsafe { - clang_parseTranslationUnit(ix.x, - fname.as_ptr(), - c_args.as_ptr(), - c_args.len() as c_int, - c_unsaved.as_mut_ptr(), - c_unsaved.len() as c_uint, - opts) - }; - if tu.is_null() { - None - } else { - Some(TranslationUnit { - x: tu, - }) - } - } - - /// Get the Clang diagnostic information associated with this translation - /// unit. - pub fn diags(&self) -> Vec { - unsafe { - let num = clang_getNumDiagnostics(self.x) as usize; - let mut diags = vec![]; - for i in 0..num { - diags.push(Diagnostic { - x: clang_getDiagnostic(self.x, i as c_uint), - }); - } - diags - } - } - - /// Get a cursor pointing to the root of this translation unit's AST. - pub fn cursor(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTranslationUnitCursor(self.x), - } - } - } - - /// Is this the null translation unit? - pub fn is_null(&self) -> bool { - self.x.is_null() - } - - /// Invoke Clang's lexer on this translation unit and get the stream of - /// tokens that come out. - pub fn tokens(&self, cursor: &Cursor) -> Option> { - let range = cursor.extent(); - let mut tokens = vec![]; - unsafe { - let mut token_ptr = ptr::null_mut(); - let mut num_tokens: c_uint = 0; - clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens); - if token_ptr.is_null() { - return None; - } - - let token_array = slice::from_raw_parts(token_ptr, - num_tokens as usize); - for &token in token_array.iter() { - let kind = clang_getTokenKind(token); - let spelling = - cxstring_into_string(clang_getTokenSpelling(self.x, token)); - - tokens.push(Token { - kind: kind, - spelling: spelling, - }); - } - clang_disposeTokens(self.x, token_ptr, num_tokens); - } - Some(tokens) - } - - /// Convert a set of tokens from clang into `cexpr` tokens, for further - /// processing. - pub fn cexpr_tokens(&self, - cursor: &Cursor) - -> Option> { - use cexpr::token; - - let mut tokens = match self.tokens(cursor) { - Some(tokens) => tokens, - None => return None, - }; - - // FIXME(emilio): LLVM 3.9 at least always include an extra token for no - // good reason (except if we're at EOF). So we do this kind of hack, - // where we skip known-to-cause problems trailing punctuation and - // trailing keywords. - // - // This is sort of unfortunate, though :(. - // - // I'll try to get it fixed in LLVM if I have the time to submit a - // patch. - let mut trim_last_token = false; - if let Some(token) = tokens.last() { - // The starting of the next macro. - trim_last_token |= token.spelling == "#" && - token.kind == CXToken_Punctuation; - - // A following keyword of any kind, like a following declaration. - trim_last_token |= token.kind == CXToken_Keyword; - } - - if trim_last_token { - tokens.pop().unwrap(); - } - - Some(tokens.into_iter() - .filter_map(|token| { - let kind = match token.kind { - CXToken_Punctuation => token::Kind::Punctuation, - CXToken_Literal => token::Kind::Literal, - CXToken_Identifier => token::Kind::Identifier, - CXToken_Keyword => token::Kind::Keyword, - // NB: cexpr is not too happy about comments inside - // expressions, so we strip them down here. - CXToken_Comment => return None, - _ => { - panic!("Found unexpected token kind: {:?}", token.kind) - } - }; - - Some(token::Token { - kind: kind, - raw: token.spelling.into_bytes().into_boxed_slice(), - }) - }) - .collect::>()) - } -} - -impl Drop for TranslationUnit { - fn drop(&mut self) { - unsafe { - clang_disposeTranslationUnit(self.x); - } - } -} - - -/// A diagnostic message generated while parsing a translation unit. -pub struct Diagnostic { - x: CXDiagnostic, -} - -impl Diagnostic { - /// Format this diagnostic message as a string, using the given option bit - /// flags. - pub fn format(&self) -> String { - unsafe { - let opts = clang_defaultDiagnosticDisplayOptions(); - cxstring_into_string(clang_formatDiagnostic(self.x, opts)) - } - } - - /// What is the severity of this diagnostic message? - pub fn severity(&self) -> CXDiagnosticSeverity { - unsafe { clang_getDiagnosticSeverity(self.x) } - } -} - -impl Drop for Diagnostic { - /// Destroy this diagnostic message. - fn drop(&mut self) { - unsafe { - clang_disposeDiagnostic(self.x); - } - } -} - -/// A file which has not been saved to disk. -pub struct UnsavedFile { - x: CXUnsavedFile, - /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in - /// `CXUnsavedFile`. - pub name: CString, - contents: CString, -} - -impl UnsavedFile { - /// Construct a new unsaved file with the given `name` and `contents`. - pub fn new(name: &str, contents: &str) -> UnsavedFile { - let name = CString::new(name).unwrap(); - let contents = CString::new(contents).unwrap(); - let x = CXUnsavedFile { - Filename: name.as_ptr(), - Contents: contents.as_ptr(), - Length: contents.as_bytes().len() as c_ulong, - }; - UnsavedFile { - x: x, - name: name, - contents: contents, - } - } -} - -impl fmt::Debug for UnsavedFile { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "UnsavedFile(name: {:?}, contents: {:?})", - self.name, - self.contents) - } -} - -/// Convert a cursor kind into a static string. -pub fn kind_to_str(x: CXCursorKind) -> String { - unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } -} - -/// Convert a type kind to a static string. -pub fn type_to_str(x: CXTypeKind) -> String { - unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } -} - -/// Dump the Clang AST to stdout for debugging purposes. -pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { - fn print_indent>(depth: isize, s: S) { - for _ in 0..depth { - print!(" "); - } - println!("{}", s.as_ref()); - } - - fn print_cursor>(depth: isize, prefix: S, c: &Cursor) { - let prefix = prefix.as_ref(); - print_indent(depth, - format!(" {}kind = {}", prefix, kind_to_str(c.kind()))); - print_indent(depth, - format!(" {}spelling = \"{}\"", prefix, c.spelling())); - print_indent(depth, format!(" {}location = {}", prefix, c.location())); - print_indent(depth, - format!(" {}is-definition? {}", - prefix, - c.is_definition())); - print_indent(depth, - format!(" {}is-declaration? {}", - prefix, - c.is_declaration())); - print_indent(depth, - format!(" {}is-inlined-function? {}", - prefix, - c.is_inlined_function())); - - let templ_kind = c.template_kind(); - if templ_kind != CXCursor_NoDeclFound { - print_indent(depth, - format!(" {}template-kind = {}", - prefix, - kind_to_str(templ_kind))); - } - if let Some(usr) = c.usr() { - print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); - } - if let Ok(num) = c.num_args() { - print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); - } - if let Some(num) = c.num_template_args() { - print_indent(depth, - format!(" {}number-of-template-args = {}", - prefix, - num)); - } - if let Some(width) = c.bit_width() { - print_indent(depth, format!(" {}bit-width = {}", prefix, width)); - } - if let Some(ty) = c.enum_type() { - print_indent(depth, - format!(" {}enum-type = {}", - prefix, - type_to_str(ty.kind()))); - } - if let Some(val) = c.enum_val_signed() { - print_indent(depth, format!(" {}enum-val = {}", prefix, val)); - } - if let Some(ty) = c.typedef_type() { - print_indent(depth, - format!(" {}typedef-type = {}", - prefix, - type_to_str(ty.kind()))); - } - if let Some(ty) = c.ret_type() { - print_indent(depth, - format!(" {}ret-type = {}", - prefix, - type_to_str(ty.kind()))); - } - - if let Some(refd) = c.referenced() { - if refd != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "referenced.", - &refd); - } - } - - let canonical = c.canonical(); - if canonical != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "canonical.", - &canonical); - } - - if let Some(specialized) = c.specialized() { - if specialized != *c { - println!(""); - print_cursor(depth, - String::from(prefix) + "specialized.", - &specialized); - } - } - - if let Some(parent) = c.fallible_semantic_parent() { - println!(""); - print_cursor(depth, - String::from(prefix) + "semantic-parent.", - &parent); - } - } - - fn print_type>(depth: isize, prefix: S, ty: &Type) { - let prefix = prefix.as_ref(); - - let kind = ty.kind(); - print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); - if kind == CXType_Invalid { - return; - } - - print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); - - print_indent(depth, - format!(" {}spelling = \"{}\"", prefix, ty.spelling())); - let num_template_args = - unsafe { clang_Type_getNumTemplateArguments(ty.x) }; - if num_template_args >= 0 { - print_indent(depth, - format!(" {}number-of-template-args = {}", - prefix, - num_template_args)); - } - if let Some(num) = ty.num_elements() { - print_indent(depth, - format!(" {}number-of-elements = {}", prefix, num)); - } - print_indent(depth, - format!(" {}is-variadic? {}", prefix, ty.is_variadic())); - - let canonical = ty.canonical_type(); - if canonical != *ty { - println!(""); - print_type(depth, String::from(prefix) + "canonical.", &canonical); - } - - if let Some(pointee) = ty.pointee_type() { - if pointee != *ty { - println!(""); - print_type(depth, String::from(prefix) + "pointee.", &pointee); - } - } - - if let Some(elem) = ty.elem_type() { - if elem != *ty { - println!(""); - print_type(depth, String::from(prefix) + "elements.", &elem); - } - } - - if let Some(ret) = ty.ret_type() { - if ret != *ty { - println!(""); - print_type(depth, String::from(prefix) + "return.", &ret); - } - } - - let named = ty.named(); - if named != *ty && named.is_valid() { - println!(""); - print_type(depth, String::from(prefix) + "named.", &named); - } - } - - print_indent(depth, "("); - print_cursor(depth, "", c); - - println!(""); - let ty = c.cur_type(); - print_type(depth, "type.", &ty); - - let declaration = ty.declaration(); - if declaration != *c && declaration.kind() != CXCursor_NoDeclFound { - println!(""); - print_cursor(depth, "type.declaration.", &declaration); - } - - // Recurse. - let mut found_children = false; - c.visit(|s| { - if !found_children { - println!(""); - found_children = true; - } - ast_dump(&s, depth + 1) - }); - - print_indent(depth, ")"); - - CXChildVisit_Continue -} - -/// Try to extract the clang version to a string -pub fn extract_clang_version() -> String { - unsafe { cxstring_into_string(clang_getClangVersion()) } -} - -/// A wrapper for the result of evaluating an expression. -#[derive(Debug)] -pub struct EvalResult { - x: CXEvalResult, -} - -impl EvalResult { - /// Evaluate `cursor` and return the result. - pub fn new(cursor: Cursor) -> Option { - if !clang_Cursor_Evaluate::is_loaded() { - return None; - } - - // Clang has an internal assertion we can trigger if we try to evaluate - // a cursor containing a variadic template type reference. Triggering - // the assertion aborts the process, and we don't want that. Clang - // *also* doesn't expose any API for finding variadic vs non-variadic - // template type references, let alone whether a type referenced is a - // template type, instead they seem to show up as type references to an - // unexposed type. Our solution is to just flat out ban all - // `CXType_Unexposed` from evaluation. - let mut found_cant_eval = false; - cursor.visit(|c| if c.kind() == CXCursor_TypeRef && - c.cur_type().kind() == CXType_Unexposed { - found_cant_eval = true; - CXChildVisit_Break - } else { - CXChildVisit_Recurse - }); - if found_cant_eval { - return None; - } - - Some(EvalResult { - x: unsafe { clang_Cursor_Evaluate(cursor.x) }, - }) - } - - fn kind(&self) -> CXEvalResultKind { - unsafe { clang_EvalResult_getKind(self.x) } - } - - /// Try to get back the result as a double. - pub fn as_double(&self) -> Option { - match self.kind() { - CXEval_Float => { - Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) - } - _ => None, - } - } - - /// Try to get back the result as an integer. - pub fn as_int(&self) -> Option { - match self.kind() { - CXEval_Int => { - Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32) - } - _ => None, - } - } - - /// Evaluates the expression as a literal string, that may or may not be - /// valid utf-8. - pub fn as_literal_string(&self) -> Option> { - match self.kind() { - CXEval_StrLiteral => { - let ret = unsafe { - CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) - }; - Some(ret.to_bytes().to_vec()) - } - _ => None, - } - } -} - -impl Drop for EvalResult { - fn drop(&mut self) { - unsafe { clang_EvalResult_dispose(self.x) }; - } -} +//! A higher level Clang API built on top of the generated bindings in the +//! `clang_sys` module. + +#![allow(non_upper_case_globals, dead_code)] + + +use cexpr; +use clang_sys::*; +use regex; +use std::{mem, ptr, slice}; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::hash::Hash; +use std::hash::Hasher; +use std::os::raw::{c_char, c_int, c_uint, c_ulong}; + +/// A cursor into the Clang AST, pointing to an AST node. +/// +/// We call the AST node pointed to by the cursor the cursor's "referent". +#[derive(Copy, Clone)] +pub struct Cursor { + x: CXCursor, +} + +impl fmt::Debug for Cursor { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Cursor({} kind: {}, loc: {}, usr: {:?})", + self.spelling(), + kind_to_str(self.kind()), + self.location(), + self.usr()) + } +} + +impl Cursor { + /// Get the Unified Symbol Resolution for this cursor's referent, if + /// available. + /// + /// The USR can be used to compare entities across translation units. + pub fn usr(&self) -> Option { + let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; + if s.is_empty() { None } else { Some(s) } + } + + /// Is this cursor's referent a declaration? + pub fn is_declaration(&self) -> bool { + unsafe { clang_isDeclaration(self.kind()) != 0 } + } + + /// Get the null cursor, which has no referent. + pub fn null() -> Self { + Cursor { + x: unsafe { clang_getNullCursor() }, + } + } + + /// Get this cursor's referent's spelling. + pub fn spelling(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } + } + + /// Get this cursor's referent's display name. + /// + /// This is not necessarily a valid identifier. It includes extra + /// information, such as parameters for a function, etc. + pub fn display_name(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } + } + + /// Get the mangled name of this cursor's referent. + pub fn mangling(&self) -> String { + if clang_Cursor_getMangling::is_loaded() { + unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } + } else { + self.spelling() + } + } + + /// Returns whether the cursor refers to a built-in definition. + pub fn is_builtin(&self) -> bool { + let (file, _, _, _) = self.location().location(); + file.name().is_none() + } + + /// Get the `Cursor` for this cursor's referent's lexical parent. + /// + /// The lexical parent is the parent of the definition. The semantic parent + /// is the parent of the declaration. Generally, the lexical parent doesn't + /// have any effect on semantics, while the semantic parent does. + /// + /// In the following snippet, the `Foo` class would be the semantic parent + /// of the out-of-line `method` definition, while the lexical parent is the + /// translation unit. + /// + /// ```c++ + /// class Foo { + /// void method(); + /// }; + /// + /// void Foo::method() { /* ... */ } + /// ``` + pub fn lexical_parent(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCursorLexicalParent(self.x), + } + } + } + + /// Get the referent's semantic parent, if one is available. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn fallible_semantic_parent(&self) -> Option { + let sp = unsafe { + Cursor { + x: clang_getCursorSemanticParent(self.x), + } + }; + if sp == *self || !sp.is_valid() { + return None; + } + Some(sp) + } + + /// Get the referent's semantic parent. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn semantic_parent(&self) -> Cursor { + self.fallible_semantic_parent().unwrap() + } + + /// Return the number of template arguments used by this cursor's referent, + /// if the referent is either a template instantiation. Returns `None` + /// otherwise. + /// + /// NOTE: This may not return `Some` for partial template specializations, + /// see #193 and #194. + pub fn num_template_args(&self) -> Option { + // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while + // `clang_Cursor_getNumTemplateArguments` is totally unreliable. + // Therefore, try former first, and only fallback to the latter if we + // have to. + self.cur_type() + .num_template_args() + .or_else(|| { + let n: c_int = + unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; + + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None + } + }) + .or_else(|| { + let canonical = self.canonical(); + if canonical != *self { + canonical.num_template_args() + } else { + None + } + }) + } + + /// Get a cursor pointing to this referent's containing translation unit. + /// + /// Note that we shouldn't create a `TranslationUnit` struct here, because + /// bindgen assumes there will only be one of them alive at a time, and + /// disposes it on drop. That can change if this would be required, but I + /// think we can survive fine without it. + pub fn translation_unit(&self) -> Cursor { + assert!(self.is_valid()); + unsafe { + let tu = clang_Cursor_getTranslationUnit(self.x); + let cursor = Cursor { + x: clang_getTranslationUnitCursor(tu), + }; + assert!(cursor.is_valid()); + cursor + } + } + + /// Is the referent a top level construct? + pub fn is_toplevel(&self) -> bool { + let mut semantic_parent = self.fallible_semantic_parent(); + + while semantic_parent.is_some() && + (semantic_parent.unwrap().kind() == CXCursor_Namespace || + semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || + semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { + semantic_parent = semantic_parent.unwrap() + .fallible_semantic_parent(); + } + + let tu = self.translation_unit(); + // Yes, this can happen with, e.g., macro definitions. + semantic_parent == tu.fallible_semantic_parent() + } + + /// There are a few kinds of types that we need to treat specially, mainly + /// not tracking the type declaration but the location of the cursor, given + /// clang doesn't expose a proper declaration for these types. + pub fn is_template_like(&self) -> bool { + match self.kind() { + CXCursor_ClassTemplate | + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_TypeAliasTemplateDecl => true, + _ => false, + } + } + + /// Get the kind of referent this cursor is pointing to. + pub fn kind(&self) -> CXCursorKind { + self.x.kind + } + + /// Returns true is the cursor is a definition + pub fn is_definition(&self) -> bool { + unsafe { clang_isCursorDefinition(self.x) != 0 } + } + + /// Is the referent a template specialization? + pub fn is_template_specialization(&self) -> bool { + self.specialized().is_some() + } + + /// Is the referent a fully specialized template specialization without any + /// remaining free template arguments? + pub fn is_fully_specialized_template(&self) -> bool { + self.is_template_specialization() && + self.kind() != CXCursor_ClassTemplatePartialSpecialization && + self.num_template_args().unwrap_or(0) > 0 + } + + /// Is the referent a template specialization that still has remaining free + /// template arguments? + pub fn is_in_non_fully_specialized_template(&self) -> bool { + if self.is_toplevel() { + return false; + } + + let parent = self.semantic_parent(); + if parent.is_fully_specialized_template() { + return false; + } + + if !parent.is_template_like() { + return parent.is_in_non_fully_specialized_template(); + } + + return true; + } + + /// Is this cursor pointing a valid referent? + pub fn is_valid(&self) -> bool { + unsafe { clang_isInvalid(self.kind()) == 0 } + } + + /// Get the source location for the referent. + pub fn location(&self) -> SourceLocation { + unsafe { + SourceLocation { + x: clang_getCursorLocation(self.x), + } + } + } + + /// Get the source location range for the referent. + pub fn extent(&self) -> CXSourceRange { + unsafe { clang_getCursorExtent(self.x) } + } + + /// Get the raw declaration comment for this referent, if one exists. + pub fn raw_comment(&self) -> Option { + let s = unsafe { + cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) + }; + if s.is_empty() { None } else { Some(s) } + } + + /// Get the referent's parsed comment. + pub fn comment(&self) -> Comment { + unsafe { + Comment { + x: clang_Cursor_getParsedComment(self.x), + } + } + } + + /// Get the referent's type. + pub fn cur_type(&self) -> Type { + unsafe { + Type { + x: clang_getCursorType(self.x), + } + } + } + + /// Given that this cursor's referent is a reference to another type, or is + /// a declaration, get the cursor pointing to the referenced type or type of + /// the declared thing. + pub fn definition(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getCursorDefinition(self.x), + }; + + if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound { + Some(ret) + } else { + None + } + } + } + + /// Given that this cursor's referent is reference type, get the cursor + /// pointing to the referenced type. + pub fn referenced(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getCursorReferenced(self.x), + }; + + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Get the canonical cursor for this referent. + /// + /// Many types can be declared multiple times before finally being properly + /// defined. This method allows us to get the canonical cursor for the + /// referent type. + pub fn canonical(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCanonicalCursor(self.x), + } + } + } + + /// Given that this cursor points to either a template specialization or a + /// template instantiation, get a cursor pointing to the template definition + /// that is being specialized. + pub fn specialized(&self) -> Option { + unsafe { + let ret = Cursor { + x: clang_getSpecializedCursorTemplate(self.x), + }; + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Assuming that this cursor's referent is a template declaration, get the + /// kind of cursor that would be generated for its specializations. + pub fn template_kind(&self) -> CXCursorKind { + unsafe { clang_getTemplateCursorKind(self.x) } + } + + /// Traverse this cursor's referent and its children. + /// + /// Call the given function on each AST node traversed. + pub fn visit(&self, mut visitor: Visitor) + where Visitor: FnMut(Cursor) -> CXChildVisitResult, + { + unsafe { + clang_visitChildren(self.x, + visit_children::, + mem::transmute(&mut visitor)); + } + } + + /// Collect all of this cursor's children into a vec and return them. + pub fn collect_children(&self) -> Vec { + let mut children = vec![]; + self.visit(|c| { + children.push(c); + CXChildVisit_Continue + }); + children + } + + /// Does this cursor have any children? + pub fn has_children(&self) -> bool { + let mut has_children = false; + self.visit(|_| { + has_children = true; + CXChildVisit_Break + }); + has_children + } + + /// Does this cursor have at least `n` children? + pub fn has_at_least_num_children(&self, n: usize) -> bool { + assert!(n > 0); + let mut num_left = n; + self.visit(|_| { + num_left -= 1; + if num_left == 0 { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + num_left == 0 + } + + /// Returns whether the given location contains a cursor with the given + /// kind in the first level of nesting underneath (doesn't look + /// recursively). + pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { + let mut found = false; + + self.visit(|c| if c.kind() == kind { + found = true; + CXChildVisit_Break + } else { + CXChildVisit_Continue + }); + + found + } + + /// Is the referent an inlined function? + pub fn is_inlined_function(&self) -> bool { + clang_Cursor_isFunctionInlined::is_loaded() && + unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } + } + + /// Get the width of this cursor's referent bit field, or `None` if the + /// referent is not a bit field. + pub fn bit_width(&self) -> Option { + unsafe { + let w = clang_getFieldDeclBitWidth(self.x); + if w == -1 { None } else { Some(w as u32) } + } + } + + /// Get the integer representation type used to hold this cursor's referent + /// enum type. + pub fn enum_type(&self) -> Option { + unsafe { + let t = Type { + x: clang_getEnumDeclIntegerType(self.x), + }; + if t.is_valid() { Some(t) } else { None } + } + } + + /// Get the signed constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_signed(&self) -> Option { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclValue(self.x) as i64) + } else { + None + } + } + } + + /// Get the unsigned constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_unsigned(&self) -> Option { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) + } else { + None + } + } + } + + /// Given that this cursor's referent is a `typedef`, get the `Type` that is + /// being aliased. + pub fn typedef_type(&self) -> Option { + let inner = Type { + x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, + }; + + if inner.is_valid() { Some(inner) } else { None } + } + + /// Get the linkage kind for this cursor's referent. + /// + /// This only applies to functions and variables. + pub fn linkage(&self) -> CXLinkageKind { + unsafe { clang_getCursorLinkage(self.x) } + } + + /// Get the visibility of this cursor's referent. + pub fn visibility(&self) -> CXVisibilityKind { + if clang_getCursorVisibility::is_loaded() { + unsafe { clang_getCursorVisibility(self.x) } + } else { + CXVisibility_Default + } + } + + /// Given that this cursor's referent is a function, return cursors to its + /// parameters. + pub fn args(&self) -> Option> { + // XXX: We might want to use and keep num_args + // match self.kind() { + // CXCursor_FunctionDecl | + // CXCursor_CXXMethod => { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { + None + } else { + let num = w as u32; + + let mut args = vec![]; + for i in 0..num { + args.push(Cursor { + x: clang_Cursor_getArgument(self.x, i as c_uint), + }); + } + Some(args) + } + } + } + + /// Given that this cursor's referent is a function/method call or + /// declaration, return the number of arguments it takes. + /// + /// Returns -1 if the cursor's referent is not a function/method call or + /// declaration. + pub fn num_args(&self) -> Result { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { Err(()) } else { Ok(w as u32) } + } + } + + /// Get the access specifier for this cursor's referent. + pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { + unsafe { clang_getCXXAccessSpecifier(self.x) } + } + + /// Is this cursor's referent a field declaration that is marked as + /// `mutable`? + pub fn is_mutable_field(&self) -> bool { + clang_CXXField_isMutable::is_loaded() && + unsafe { clang_CXXField_isMutable(self.x) != 0 } + } + + /// Get the offset of the field represented by the Cursor. + pub fn offset_of_field(&self) -> Result { + if !clang_Cursor_getOffsetOfField::is_loaded() { + return Err(LayoutError::from(-1)); + } + + let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; + + if offset < 0 { + Err(LayoutError::from(offset as i32)) + } else { + Ok(offset as usize) + } + } + + /// Is this cursor's referent a member function that is declared `static`? + pub fn method_is_static(&self) -> bool { + unsafe { clang_CXXMethod_isStatic(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_const(&self) -> bool { + unsafe { clang_CXXMethod_isConst(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_virtual(&self) -> bool { + unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } + } + + /// Is this cursor's referent a struct or class with virtual members? + pub fn is_virtual_base(&self) -> bool { + unsafe { clang_isVirtualBase(self.x) != 0 } + } + + /// Try to evaluate this cursor. + pub fn evaluate(&self) -> Option { + EvalResult::new(*self) + } + + /// Return the result type for this cursor + pub fn ret_type(&self) -> Option { + let rt = Type { + x: unsafe { clang_getCursorResultType(self.x) }, + }; + if rt.is_valid() { Some(rt) } else { None } + } +} + +/// Checks whether the name looks like an identifier, i.e. is alphanumeric +/// (including '_') and does not start with a digit. +pub fn is_valid_identifier(name: &str) -> bool { + let mut chars = name.chars(); + let first_valid = chars.next() + .map(|c| c.is_alphabetic() || c == '_') + .unwrap_or(false); + + first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') +} + +extern "C" fn visit_children(cur: CXCursor, + _parent: CXCursor, + data: CXClientData) + -> CXChildVisitResult + where Visitor: FnMut(Cursor) -> CXChildVisitResult, +{ + let func: &mut Visitor = unsafe { mem::transmute(data) }; + let child = Cursor { + x: cur, + }; + + (*func)(child) +} + +impl PartialEq for Cursor { + fn eq(&self, other: &Cursor) -> bool { + unsafe { clang_equalCursors(self.x, other.x) == 1 } + } +} + +impl Eq for Cursor {} + +impl Hash for Cursor { + fn hash(&self, state: &mut H) { + unsafe { clang_hashCursor(self.x) }.hash(state) + } +} + +/// The type of a node in clang's AST. +#[derive(Clone, Copy)] +pub struct Type { + x: CXType, +} + +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + unsafe { clang_equalTypes(self.x, other.x) != 0 } + } +} + +impl Eq for Type {} + +impl fmt::Debug for Type { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})", + self.spelling(), + type_to_str(self.kind()), + self.call_conv(), + self.declaration(), + self.declaration().canonical()) + } +} + +/// An error about the layout of a struct, class, or type. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum LayoutError { + /// Asked for the layout of an invalid type. + Invalid, + /// Asked for the layout of an incomplete type. + Incomplete, + /// Asked for the layout of a dependent type. + Dependent, + /// Asked for the layout of a type that does not have constant size. + NotConstantSize, + /// Asked for the layout of a field in a type that does not have such a + /// field. + InvalidFieldName, + /// An unknown layout error. + Unknown, +} + +impl ::std::convert::From for LayoutError { + fn from(val: i32) -> Self { + use self::LayoutError::*; + + match val { + CXTypeLayoutError_Invalid => Invalid, + CXTypeLayoutError_Incomplete => Incomplete, + CXTypeLayoutError_Dependent => Dependent, + CXTypeLayoutError_NotConstantSize => NotConstantSize, + CXTypeLayoutError_InvalidFieldName => InvalidFieldName, + _ => Unknown, + } + } +} + +impl Type { + /// Get this type's kind. + pub fn kind(&self) -> CXTypeKind { + self.x.kind + } + + /// Get a cursor pointing to this type's declaration. + pub fn declaration(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTypeDeclaration(self.x), + } + } + } + + /// Get the canonical declaration of this type, if it is available. + pub fn canonical_declaration(&self, + location: Option<&Cursor>) + -> Option { + let mut declaration = self.declaration(); + if !declaration.is_valid() { + if let Some(location) = location { + let mut location = *location; + if let Some(referenced) = location.referenced() { + location = referenced; + } + if location.is_template_like() { + declaration = location; + } + } + } + + let canonical = declaration.canonical(); + if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound { + Some(CanonicalTypeDeclaration(*self, canonical)) + } else { + None + } + } + + /// Get a raw display name for this type. + pub fn spelling(&self) -> String { + let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; + // Clang 5.0 introduced changes in the spelling API so it returned the + // full qualified name. Let's undo that here. + if s.split("::").all(|s| is_valid_identifier(s)) { + if let Some(s) = s.split("::").last() { + return s.to_owned(); + } + } + + s + } + + /// Is this type const qualified? + pub fn is_const(&self) -> bool { + unsafe { clang_isConstQualifiedType(self.x) != 0 } + } + + /// What is the size of this type? Paper over invalid types by returning `0` + /// for them. + pub fn size(&self) -> usize { + unsafe { + let val = clang_Type_getSizeOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the size of this type? + pub fn fallible_size(&self) -> Result { + let val = unsafe { clang_Type_getSizeOf(self.x) }; + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + + /// What is the alignment of this type? Paper over invalid types by + /// returning `0`. + pub fn align(&self) -> usize { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the alignment of this type? + pub fn fallible_align(&self) -> Result { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + } + + /// Get the layout for this type, or an error describing why it does not + /// have a valid layout. + pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { + use ir::layout::Layout; + let size = try!(self.fallible_size()); + let align = try!(self.fallible_align()); + Ok(Layout::new(size, align)) + } + + /// Get the number of template arguments this type has, or `None` if it is + /// not some kind of template. + pub fn num_template_args(&self) -> Option { + let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None + } + } + + /// If this type is a class template specialization, return its + /// template arguments. Otherwise, return None. + pub fn template_args(&self) -> Option { + self.num_template_args().map(|n| { + TypeTemplateArgIterator { + x: self.x, + length: n, + index: 0, + } + }) + } + + /// Given that this type is a pointer type, return the type that it points + /// to. + pub fn pointee_type(&self) -> Option { + match self.kind() { + CXType_Pointer | + CXType_RValueReference | + CXType_LValueReference | + CXType_MemberPointer | + CXType_ObjCObjectPointer => { + let ret = Type { + x: unsafe { clang_getPointeeType(self.x) }, + }; + debug_assert!(ret.is_valid()); + Some(ret) + } + _ => None, + } + } + + /// Given that this type is an array, vector, or complex type, return the + /// type of its elements. + pub fn elem_type(&self) -> Option { + let current_type = Type { + x: unsafe { clang_getElementType(self.x) }, + }; + if current_type.is_valid() { + Some(current_type) + } else { + None + } + } + + /// Given that this type is an array or vector type, return its number of + /// elements. + pub fn num_elements(&self) -> Option { + let num_elements_returned = unsafe { clang_getNumElements(self.x) }; + if num_elements_returned != -1 { + Some(num_elements_returned as usize) + } else { + None + } + } + + /// Get the canonical version of this type. This sees through `typdef`s and + /// aliases to get the underlying, canonical type. + pub fn canonical_type(&self) -> Type { + unsafe { + Type { + x: clang_getCanonicalType(self.x), + } + } + } + + /// Is this type a variadic function type? + pub fn is_variadic(&self) -> bool { + unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } + } + + /// Given that this type is a function type, get the type of its return + /// value. + pub fn ret_type(&self) -> Option { + let rt = Type { + x: unsafe { clang_getResultType(self.x) }, + }; + if rt.is_valid() { Some(rt) } else { None } + } + + /// Given that this type is a function type, get its calling convention. If + /// this is not a function type, `CXCallingConv_Invalid` is returned. + pub fn call_conv(&self) -> CXCallingConv { + unsafe { clang_getFunctionTypeCallingConv(self.x) } + } + + /// For elaborated types (types which use `class`, `struct`, or `union` to + /// disambiguate types from local bindings), get the underlying type. + pub fn named(&self) -> Type { + unsafe { + Type { + x: if clang_Type_getNamedType::is_loaded() { + clang_Type_getNamedType(self.x) + } else { + self.x + }, + } + } + } + + /// Is this a valid type? + pub fn is_valid(&self) -> bool { + self.kind() != CXType_Invalid + } + + /// Is this a valid and exposed type? + pub fn is_valid_and_exposed(&self) -> bool { + self.is_valid() && self.kind() != CXType_Unexposed + } + + /// Is this type a fully instantiated template? + pub fn is_fully_instantiated_template(&self) -> bool { + // Yep, the spelling of this containing type-parameter is extremely + // nasty... But can happen in . Unfortunately I couldn't + // reduce it enough :( + self.template_args().map_or(false, |args| args.len() > 0) && + match self.declaration().kind() { + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_TypeAliasTemplateDecl | + CXCursor_TemplateTemplateParameter => false, + _ => true, + } + } + + /// Is this type an associated template type? Eg `T::Associated` in + /// this example: + /// + /// ```c++ + /// template + /// class Foo { + /// typename T::Associated member; + /// }; + /// ``` + pub fn is_associated_type(&self) -> bool { + // This is terrible :( + fn hacky_parse_associated_type>(spelling: S) -> bool { + lazy_static! { + static ref ASSOC_TYPE_RE: regex::Regex = + regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap(); + } + ASSOC_TYPE_RE.is_match(spelling.as_ref()) + } + + self.kind() == CXType_Unexposed && + (hacky_parse_associated_type(self.spelling()) || + hacky_parse_associated_type(self.canonical_type().spelling())) + } +} + +/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its +/// cursor is the canonical declaration for its type. If you have a +/// `CanonicalTypeDeclaration` instance, you know for sure that the type and +/// cursor match up in a canonical declaration relationship, and it simply +/// cannot be otherwise. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CanonicalTypeDeclaration(Type, Cursor); + +impl CanonicalTypeDeclaration { + /// Get the type. + pub fn ty(&self) -> &Type { + &self.0 + } + + /// Get the type's canonical declaration cursor. + pub fn cursor(&self) -> &Cursor { + &self.1 + } +} + +/// An iterator for a type's template arguments. +pub struct TypeTemplateArgIterator { + x: CXType, + length: u32, + index: u32, +} + +impl Iterator for TypeTemplateArgIterator { + type Item = Type; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index as c_uint; + self.index += 1; + Some(Type { + x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, + }) + } else { + None + } + } +} + +impl ExactSizeIterator for TypeTemplateArgIterator { + fn len(&self) -> usize { + assert!(self.index <= self.length); + (self.length - self.index) as usize + } +} + +/// A `SourceLocation` is a file, line, column, and byte offset location for +/// some source text. +pub struct SourceLocation { + x: CXSourceLocation, +} + +impl SourceLocation { + /// Get the (file, line, column, byte offset) tuple for this source + /// location. + pub fn location(&self) -> (File, usize, usize, usize) { + unsafe { + let mut file = mem::zeroed(); + let mut line = 0; + let mut col = 0; + let mut off = 0; + clang_getSpellingLocation(self.x, + &mut file, + &mut line, + &mut col, + &mut off); + (File { + x: file, + }, + line as usize, + col as usize, + off as usize) + } + } +} + +impl fmt::Display for SourceLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (file, line, col, _) = self.location(); + if let Some(name) = file.name() { + write!(f, "{}:{}:{}", name, line, col) + } else { + "builtin definitions".fmt(f) + } + } +} + +/// A comment in the source text. +/// +/// Comments are sort of parsed by Clang, and have a tree structure. +pub struct Comment { + x: CXComment, +} + +impl Comment { + /// What kind of comment is this? + pub fn kind(&self) -> CXCommentKind { + unsafe { clang_Comment_getKind(self.x) } + } + + /// Get this comment's children comment + pub fn get_children(&self) -> CommentChildrenIterator { + CommentChildrenIterator { + parent: self.x, + length: unsafe { clang_Comment_getNumChildren(self.x) }, + index: 0, + } + } + + /// Given that this comment is the start or end of an HTML tag, get its tag + /// name. + pub fn get_tag_name(&self) -> String { + unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } + } + + /// Given that this comment is an HTML start tag, get its attributes. + pub fn get_tag_attrs(&self) -> CommentAttributesIterator { + CommentAttributesIterator { + x: self.x, + length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, + index: 0, + } + } +} + +/// An iterator for a comment's children +pub struct CommentChildrenIterator { + parent: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentChildrenIterator { + type Item = Comment; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(Comment { + x: unsafe { clang_Comment_getChild(self.parent, idx) }, + }) + } else { + None + } + } +} + +/// An HTML start tag comment attribute +pub struct CommentAttribute { + /// HTML start tag attribute name + pub name: String, + /// HTML start tag attribute value + pub value: String, +} + +/// An iterator for a comment's attributes +pub struct CommentAttributesIterator { + x: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentAttributesIterator { + type Item = CommentAttribute; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(CommentAttribute { + name: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrName(self.x, idx)) + }, + value: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrValue(self.x, idx)) + }, + }) + } else { + None + } + } +} + +/// A source file. +pub struct File { + x: CXFile, +} + +impl File { + /// Get the name of this source file. + pub fn name(&self) -> Option { + if self.x.is_null() { + return None; + } + Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) + } +} + +fn cxstring_into_string(s: CXString) -> String { + if s.data.is_null() { + return "".to_owned(); + } + unsafe { + let c_str = CStr::from_ptr(clang_getCString(s) as *const _); + let ret = c_str.to_string_lossy().into_owned(); + clang_disposeString(s); + ret + } +} + +/// An `Index` is an environment for a set of translation units that will +/// typically end up linked together in one final binary. +pub struct Index { + x: CXIndex, +} + +impl Index { + /// Construct a new `Index`. + /// + /// The `pch` parameter controls whether declarations in pre-compiled + /// headers are included when enumerating a translation unit's "locals". + /// + /// The `diag` parameter controls whether debugging diagnostics are enabled. + pub fn new(pch: bool, diag: bool) -> Index { + unsafe { + Index { + x: clang_createIndex(pch as c_int, diag as c_int), + } + } + } +} + +impl fmt::Debug for Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Index {{ }}") + } +} + +impl Drop for Index { + fn drop(&mut self) { + unsafe { + clang_disposeIndex(self.x); + } + } +} + +/// A token emitted by clang's lexer. +#[derive(Debug)] +pub struct Token { + /// The kind of token this is. + pub kind: CXTokenKind, + /// A display name for this token. + pub spelling: String, +} + +/// A translation unit (or "compilation unit"). +pub struct TranslationUnit { + x: CXTranslationUnit, +} + +impl fmt::Debug for TranslationUnit { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "TranslationUnit {{ }}") + } +} + +impl TranslationUnit { + /// Parse a source file into a translation unit. + pub fn parse(ix: &Index, + file: &str, + cmd_args: &[String], + unsaved: &[UnsavedFile], + opts: CXTranslationUnit_Flags) + -> Option { + let fname = CString::new(file).unwrap(); + let _c_args: Vec = + cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect(); + let c_args: Vec<*const c_char> = + _c_args.iter().map(|s| s.as_ptr()).collect(); + let mut c_unsaved: Vec = + unsaved.iter().map(|f| f.x).collect(); + let tu = unsafe { + clang_parseTranslationUnit(ix.x, + fname.as_ptr(), + c_args.as_ptr(), + c_args.len() as c_int, + c_unsaved.as_mut_ptr(), + c_unsaved.len() as c_uint, + opts) + }; + if tu.is_null() { + None + } else { + Some(TranslationUnit { + x: tu, + }) + } + } + + /// Get the Clang diagnostic information associated with this translation + /// unit. + pub fn diags(&self) -> Vec { + unsafe { + let num = clang_getNumDiagnostics(self.x) as usize; + let mut diags = vec![]; + for i in 0..num { + diags.push(Diagnostic { + x: clang_getDiagnostic(self.x, i as c_uint), + }); + } + diags + } + } + + /// Get a cursor pointing to the root of this translation unit's AST. + pub fn cursor(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTranslationUnitCursor(self.x), + } + } + } + + /// Is this the null translation unit? + pub fn is_null(&self) -> bool { + self.x.is_null() + } + + /// Invoke Clang's lexer on this translation unit and get the stream of + /// tokens that come out. + pub fn tokens(&self, cursor: &Cursor) -> Option> { + let range = cursor.extent(); + let mut tokens = vec![]; + unsafe { + let mut token_ptr = ptr::null_mut(); + let mut num_tokens: c_uint = 0; + clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens); + if token_ptr.is_null() { + return None; + } + + let token_array = slice::from_raw_parts(token_ptr, + num_tokens as usize); + for &token in token_array.iter() { + let kind = clang_getTokenKind(token); + let spelling = + cxstring_into_string(clang_getTokenSpelling(self.x, token)); + + tokens.push(Token { + kind: kind, + spelling: spelling, + }); + } + clang_disposeTokens(self.x, token_ptr, num_tokens); + } + Some(tokens) + } + + /// Convert a set of tokens from clang into `cexpr` tokens, for further + /// processing. + pub fn cexpr_tokens(&self, + cursor: &Cursor) + -> Option> { + use cexpr::token; + + let mut tokens = match self.tokens(cursor) { + Some(tokens) => tokens, + None => return None, + }; + + // FIXME(emilio): LLVM 3.9 at least always include an extra token for no + // good reason (except if we're at EOF). So we do this kind of hack, + // where we skip known-to-cause problems trailing punctuation and + // trailing keywords. + // + // This is sort of unfortunate, though :(. + // + // I'll try to get it fixed in LLVM if I have the time to submit a + // patch. + let mut trim_last_token = false; + if let Some(token) = tokens.last() { + // The starting of the next macro. + trim_last_token |= token.spelling == "#" && + token.kind == CXToken_Punctuation; + + // A following keyword of any kind, like a following declaration. + trim_last_token |= token.kind == CXToken_Keyword; + } + + if trim_last_token { + tokens.pop().unwrap(); + } + + Some(tokens.into_iter() + .filter_map(|token| { + let kind = match token.kind { + CXToken_Punctuation => token::Kind::Punctuation, + CXToken_Literal => token::Kind::Literal, + CXToken_Identifier => token::Kind::Identifier, + CXToken_Keyword => token::Kind::Keyword, + // NB: cexpr is not too happy about comments inside + // expressions, so we strip them down here. + CXToken_Comment => return None, + _ => { + panic!("Found unexpected token kind: {:?}", token.kind) + } + }; + + Some(token::Token { + kind: kind, + raw: token.spelling.into_bytes().into_boxed_slice(), + }) + }) + .collect::>()) + } +} + +impl Drop for TranslationUnit { + fn drop(&mut self) { + unsafe { + clang_disposeTranslationUnit(self.x); + } + } +} + + +/// A diagnostic message generated while parsing a translation unit. +pub struct Diagnostic { + x: CXDiagnostic, +} + +impl Diagnostic { + /// Format this diagnostic message as a string, using the given option bit + /// flags. + pub fn format(&self) -> String { + unsafe { + let opts = clang_defaultDiagnosticDisplayOptions(); + cxstring_into_string(clang_formatDiagnostic(self.x, opts)) + } + } + + /// What is the severity of this diagnostic message? + pub fn severity(&self) -> CXDiagnosticSeverity { + unsafe { clang_getDiagnosticSeverity(self.x) } + } +} + +impl Drop for Diagnostic { + /// Destroy this diagnostic message. + fn drop(&mut self) { + unsafe { + clang_disposeDiagnostic(self.x); + } + } +} + +/// A file which has not been saved to disk. +pub struct UnsavedFile { + x: CXUnsavedFile, + /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in + /// `CXUnsavedFile`. + pub name: CString, + contents: CString, +} + +impl UnsavedFile { + /// Construct a new unsaved file with the given `name` and `contents`. + pub fn new(name: &str, contents: &str) -> UnsavedFile { + let name = CString::new(name).unwrap(); + let contents = CString::new(contents).unwrap(); + let x = CXUnsavedFile { + Filename: name.as_ptr(), + Contents: contents.as_ptr(), + Length: contents.as_bytes().len() as c_ulong, + }; + UnsavedFile { + x: x, + name: name, + contents: contents, + } + } +} + +impl fmt::Debug for UnsavedFile { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "UnsavedFile(name: {:?}, contents: {:?})", + self.name, + self.contents) + } +} + +/// Convert a cursor kind into a static string. +pub fn kind_to_str(x: CXCursorKind) -> String { + unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } +} + +/// Convert a type kind to a static string. +pub fn type_to_str(x: CXTypeKind) -> String { + unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } +} + +/// Dump the Clang AST to stdout for debugging purposes. +pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { + fn print_indent>(depth: isize, s: S) { + for _ in 0..depth { + print!(" "); + } + println!("{}", s.as_ref()); + } + + fn print_cursor>(depth: isize, prefix: S, c: &Cursor) { + let prefix = prefix.as_ref(); + print_indent(depth, + format!(" {}kind = {}", prefix, kind_to_str(c.kind()))); + print_indent(depth, + format!(" {}spelling = \"{}\"", prefix, c.spelling())); + print_indent(depth, format!(" {}location = {}", prefix, c.location())); + print_indent(depth, + format!(" {}is-definition? {}", + prefix, + c.is_definition())); + print_indent(depth, + format!(" {}is-declaration? {}", + prefix, + c.is_declaration())); + print_indent(depth, + format!(" {}is-inlined-function? {}", + prefix, + c.is_inlined_function())); + + let templ_kind = c.template_kind(); + if templ_kind != CXCursor_NoDeclFound { + print_indent(depth, + format!(" {}template-kind = {}", + prefix, + kind_to_str(templ_kind))); + } + if let Some(usr) = c.usr() { + print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); + } + if let Ok(num) = c.num_args() { + print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); + } + if let Some(num) = c.num_template_args() { + print_indent(depth, + format!(" {}number-of-template-args = {}", + prefix, + num)); + } + if let Some(width) = c.bit_width() { + print_indent(depth, format!(" {}bit-width = {}", prefix, width)); + } + if let Some(ty) = c.enum_type() { + print_indent(depth, + format!(" {}enum-type = {}", + prefix, + type_to_str(ty.kind()))); + } + if let Some(val) = c.enum_val_signed() { + print_indent(depth, format!(" {}enum-val = {}", prefix, val)); + } + if let Some(ty) = c.typedef_type() { + print_indent(depth, + format!(" {}typedef-type = {}", + prefix, + type_to_str(ty.kind()))); + } + if let Some(ty) = c.ret_type() { + print_indent(depth, + format!(" {}ret-type = {}", + prefix, + type_to_str(ty.kind()))); + } + + if let Some(refd) = c.referenced() { + if refd != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "referenced.", + &refd); + } + } + + let canonical = c.canonical(); + if canonical != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "canonical.", + &canonical); + } + + if let Some(specialized) = c.specialized() { + if specialized != *c { + println!(""); + print_cursor(depth, + String::from(prefix) + "specialized.", + &specialized); + } + } + + if let Some(parent) = c.fallible_semantic_parent() { + println!(""); + print_cursor(depth, + String::from(prefix) + "semantic-parent.", + &parent); + } + } + + fn print_type>(depth: isize, prefix: S, ty: &Type) { + let prefix = prefix.as_ref(); + + let kind = ty.kind(); + print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); + if kind == CXType_Invalid { + return; + } + + print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); + + print_indent(depth, + format!(" {}spelling = \"{}\"", prefix, ty.spelling())); + let num_template_args = + unsafe { clang_Type_getNumTemplateArguments(ty.x) }; + if num_template_args >= 0 { + print_indent(depth, + format!(" {}number-of-template-args = {}", + prefix, + num_template_args)); + } + if let Some(num) = ty.num_elements() { + print_indent(depth, + format!(" {}number-of-elements = {}", prefix, num)); + } + print_indent(depth, + format!(" {}is-variadic? {}", prefix, ty.is_variadic())); + + let canonical = ty.canonical_type(); + if canonical != *ty { + println!(""); + print_type(depth, String::from(prefix) + "canonical.", &canonical); + } + + if let Some(pointee) = ty.pointee_type() { + if pointee != *ty { + println!(""); + print_type(depth, String::from(prefix) + "pointee.", &pointee); + } + } + + if let Some(elem) = ty.elem_type() { + if elem != *ty { + println!(""); + print_type(depth, String::from(prefix) + "elements.", &elem); + } + } + + if let Some(ret) = ty.ret_type() { + if ret != *ty { + println!(""); + print_type(depth, String::from(prefix) + "return.", &ret); + } + } + + let named = ty.named(); + if named != *ty && named.is_valid() { + println!(""); + print_type(depth, String::from(prefix) + "named.", &named); + } + } + + print_indent(depth, "("); + print_cursor(depth, "", c); + + println!(""); + let ty = c.cur_type(); + print_type(depth, "type.", &ty); + + let declaration = ty.declaration(); + if declaration != *c && declaration.kind() != CXCursor_NoDeclFound { + println!(""); + print_cursor(depth, "type.declaration.", &declaration); + } + + // Recurse. + let mut found_children = false; + c.visit(|s| { + if !found_children { + println!(""); + found_children = true; + } + ast_dump(&s, depth + 1) + }); + + print_indent(depth, ")"); + + CXChildVisit_Continue +} + +/// Try to extract the clang version to a string +pub fn extract_clang_version() -> String { + unsafe { cxstring_into_string(clang_getClangVersion()) } +} + +/// A wrapper for the result of evaluating an expression. +#[derive(Debug)] +pub struct EvalResult { + x: CXEvalResult, +} + +impl EvalResult { + /// Evaluate `cursor` and return the result. + pub fn new(cursor: Cursor) -> Option { + if !clang_Cursor_Evaluate::is_loaded() { + return None; + } + + // Clang has an internal assertion we can trigger if we try to evaluate + // a cursor containing a variadic template type reference. Triggering + // the assertion aborts the process, and we don't want that. Clang + // *also* doesn't expose any API for finding variadic vs non-variadic + // template type references, let alone whether a type referenced is a + // template type, instead they seem to show up as type references to an + // unexposed type. Our solution is to just flat out ban all + // `CXType_Unexposed` from evaluation. + let mut found_cant_eval = false; + cursor.visit(|c| if c.kind() == CXCursor_TypeRef && + c.cur_type().kind() == CXType_Unexposed { + found_cant_eval = true; + CXChildVisit_Break + } else { + CXChildVisit_Recurse + }); + if found_cant_eval { + return None; + } + + Some(EvalResult { + x: unsafe { clang_Cursor_Evaluate(cursor.x) }, + }) + } + + fn kind(&self) -> CXEvalResultKind { + unsafe { clang_EvalResult_getKind(self.x) } + } + + /// Try to get back the result as a double. + pub fn as_double(&self) -> Option { + match self.kind() { + CXEval_Float => { + Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) + } + _ => None, + } + } + + /// Try to get back the result as an integer. + pub fn as_int(&self) -> Option { + match self.kind() { + CXEval_Int => { + Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32) + } + _ => None, + } + } + + /// Evaluates the expression as a literal string, that may or may not be + /// valid utf-8. + pub fn as_literal_string(&self) -> Option> { + match self.kind() { + CXEval_StrLiteral => { + let ret = unsafe { + CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) + }; + Some(ret.to_bytes().to_vec()) + } + _ => None, + } + } +} + +impl Drop for EvalResult { + fn drop(&mut self) { + unsafe { clang_EvalResult_dispose(self.x) }; + } +} diff --git a/src/main.rs b/src/main.rs index 5338f574fc..2ba2b1394a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,12 +22,12 @@ use options::builder_from_flags; pub fn main() { #[cfg(feature="logging")] log::set_logger(|max_log_level| { - use env_logger::Logger; - let env_logger = Logger::new(); - max_log_level.set(env_logger.filter()); - Box::new(env_logger) - }) - .expect("Failed to set logger."); + use env_logger::Logger; + let env_logger = Logger::new(); + max_log_level.set(env_logger.filter()); + Box::new(env_logger) + }) + .expect("Failed to set logger."); let bind_args: Vec<_> = env::args().collect(); @@ -52,8 +52,8 @@ pub fn main() { Ok((builder, output, verbose)) => { let builder_result = panic::catch_unwind(|| { - builder.generate().expect("Unable to generate bindings") - }); + builder.generate().expect("Unable to generate bindings") + }); if builder_result.is_err() { if verbose { @@ -63,9 +63,9 @@ pub fn main() { } let mut bindings = builder_result.unwrap(); - bindings.write(output).expect("Unable to write output"); - bindings - .write_dummy_uses() + bindings.write(output) + .expect("Unable to write output"); + bindings.write_dummy_uses() .expect("Unable to write dummy uses to file."); } Err(error) => { diff --git a/src/options.rs b/src/options.rs index 4948d0fdcf..9072abd820 100644 --- a/src/options.rs +++ b/src/options.rs @@ -7,7 +7,7 @@ use std::io::{self, Error, ErrorKind}; pub fn builder_from_flags (args: I) -> Result<(Builder, Box, bool), io::Error> - where I: Iterator + where I: Iterator, { let matches = App::new("bindgen") .version(env!("CARGO_PKG_VERSION")) From 0167a29939b6a876b8441576342e48d206d04996 Mon Sep 17 00:00:00 2001 From: Date: Mon, 17 Apr 2017 18:33:43 -0400 Subject: [PATCH 12/18] redoing commit --- src/codegen/mod.rs | 6662 ++++++++--------- .../tests/anonymous-template-types.rs | 70 +- tests/expectations/tests/class_nested.rs | 264 +- tests/expectations/tests/class_with_dtor.rs | 94 +- tests/expectations/tests/const_tparam.rs | 32 +- .../tests/default-template-parameter.rs | 64 +- .../tests/forward-declaration-autoptr.rs | 82 +- .../forward-inherit-struct-with-fields.rs | 50 +- tests/expectations/tests/inherit_named.rs | 40 +- ...issue-584-stylo-template-analysis-panic.rs | 162 +- tests/expectations/tests/namespace.rs | 206 +- tests/expectations/tests/nsStyleAutoArray.rs | 60 +- .../tests/replace_template_alias.rs | 38 +- tests/expectations/tests/replaces_double.rs | 38 +- .../tests/template-param-usage-0.rs | 30 +- .../tests/template-param-usage-10.rs | 58 +- .../tests/template-param-usage-12.rs | 50 +- .../tests/template-param-usage-13.rs | 42 +- .../tests/template-param-usage-15.rs | 48 +- .../tests/template-param-usage-2.rs | 48 +- .../tests/template-param-usage-3.rs | 54 +- .../tests/template-param-usage-4.rs | 40 +- .../tests/template-param-usage-5.rs | 32 +- .../tests/template-param-usage-7.rs | 36 +- .../tests/template-param-usage-8.rs | 38 +- .../tests/template-param-usage-9.rs | 48 +- tests/expectations/tests/template.rs | 558 +- tests/expectations/tests/template_alias.rs | 32 +- .../tests/template_alias_namespace.rs | 58 +- .../template_typedef_transitive_param.rs | 42 +- ..._alias_partial_template_especialization.rs | 32 +- tests/expectations/tests/using.rs | 36 +- tests/expectations/tests/what_is_going_on.rs | 66 +- tests/expectations/tests/whitelist_basic.rs | 50 +- tests/stylo_sanity.rs | 1096 +-- tests/tests.rs | 342 +- 36 files changed, 5349 insertions(+), 5349 deletions(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 374a600ca3..8c860528fd 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,3331 +1,3331 @@ -mod error; -mod helpers; -mod struct_layout; - -use self::helpers::{BlobTyBuilder, attributes}; -use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; -use self::struct_layout::{align_to, bytes_from_bits}; -use aster; - -use ir::annotations::FieldAccessorKind; -use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; -use ir::context::{BindgenContext, ItemId}; -use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use ir::dot; -use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; -use ir::function::{Function, FunctionSig}; -use ir::int::IntKind; -use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath, - ItemSet}; -use ir::item_kind::ItemKind; -use ir::layout::Layout; -use ir::module::Module; -use ir::objc::{ObjCInterface, ObjCMethod}; -use ir::template::{AsNamed, TemplateInstantiation}; -use ir::ty::{TemplateDeclaration, Type, TypeKind}; -use ir::var::Var; - -use std::borrow::Cow; -use std::cell::Cell; -use std::cmp; -use std::collections::{HashSet, VecDeque}; -use std::collections::hash_map::{Entry, HashMap}; -use std::fmt::Write; -use std::mem; -use std::ops; -use syntax::abi::Abi; -use syntax::ast; -use syntax::codemap::{Span, respan}; -use syntax::ptr::P; - -fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { - if !ctx.options().enable_cxx_namespaces { - return 0; - } - - item.ancestors(ctx) - .filter(|id| ctx.resolve_item(*id).is_module()) - .fold(1, |i, _| i + 1) -} - -fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec { - let mut path = vec![ctx.rust_ident_raw("self")]; - - if ctx.options().enable_cxx_namespaces { - let super_ = ctx.rust_ident_raw("super"); - - for _ in 0..root_import_depth(ctx, item) { - path.push(super_.clone()); - } - } - - path -} - -fn root_import(ctx: &BindgenContext, module: &Item) -> P { - assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); - assert!(module.is_module()); - - let mut path = top_level_path(ctx, module); - - let root = ctx.root_module().canonical_name(ctx); - let root_ident = ctx.rust_ident(&root); - path.push(root_ident); - - let use_root = aster::AstBuilder::new() - .item() - .use_() - .ids(path) - .build() - .build(); - - quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() -} - -struct CodegenResult<'a> { - items: Vec>, - - /// A monotonic counter used to add stable unique id's to stuff that doesn't - /// need to be referenced by anything. - codegen_id: &'a Cell, - - /// Whether an union has been generated at least once. - saw_union: bool, - - /// Whether an incomplete array has been generated at least once. - saw_incomplete_array: bool, - - /// Whether Objective C types have been seen at least once. - saw_objc: bool, - - items_seen: HashSet, - /// The set of generated function/var names, needed because in C/C++ is - /// legal to do something like: - /// - /// ```c++ - /// extern "C" { - /// void foo(); - /// extern int bar; - /// } - /// - /// extern "C" { - /// void foo(); - /// extern int bar; - /// } - /// ``` - /// - /// Being these two different declarations. - functions_seen: HashSet, - vars_seen: HashSet, - - /// Used for making bindings to overloaded functions. Maps from a canonical - /// function name to the number of overloads we have already codegen'd for - /// that name. This lets us give each overload a unique suffix. - overload_counters: HashMap, -} - -impl<'a> CodegenResult<'a> { - fn new(codegen_id: &'a Cell) -> Self { - CodegenResult { - items: vec![], - saw_union: false, - saw_incomplete_array: false, - saw_objc: false, - codegen_id: codegen_id, - items_seen: Default::default(), - functions_seen: Default::default(), - vars_seen: Default::default(), - overload_counters: Default::default(), - } - } - - fn saw_union(&mut self) { - self.saw_union = true; - } - - fn saw_incomplete_array(&mut self) { - self.saw_incomplete_array = true; - } - - fn saw_objc(&mut self) { - self.saw_objc = true; - } - - fn seen(&self, item: ItemId) -> bool { - self.items_seen.contains(&item) - } - - fn set_seen(&mut self, item: ItemId) { - self.items_seen.insert(item); - } - - fn seen_function(&self, name: &str) -> bool { - self.functions_seen.contains(name) - } - - fn saw_function(&mut self, name: &str) { - self.functions_seen.insert(name.into()); - } - - /// Get the overload number for the given function name. Increments the - /// counter internally so the next time we ask for the overload for this - /// name, we get the incremented value, and so on. - fn overload_number(&mut self, name: &str) -> u32 { - let mut counter = - self.overload_counters.entry(name.into()).or_insert(0); - let number = *counter; - *counter += 1; - number - } - - fn seen_var(&self, name: &str) -> bool { - self.vars_seen.contains(name) - } - - fn saw_var(&mut self, name: &str) { - self.vars_seen.insert(name.into()); - } - - fn inner(&mut self, cb: F) -> Vec> - where F: FnOnce(&mut Self), - { - let mut new = Self::new(self.codegen_id); - - cb(&mut new); - - self.saw_union |= new.saw_union; - self.saw_incomplete_array |= new.saw_incomplete_array; - self.saw_objc |= new.saw_objc; - - new.items - } -} - -impl<'a> ops::Deref for CodegenResult<'a> { - type Target = Vec>; - - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl<'a> ops::DerefMut for CodegenResult<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.items - } -} - -struct ForeignModBuilder { - inner: ast::ForeignMod, -} - -impl ForeignModBuilder { - fn new(abi: Abi) -> Self { - ForeignModBuilder { - inner: ast::ForeignMod { - abi: abi, - items: vec![], - }, - } - } - - fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { - self.inner.items.push(item); - self - } - - #[allow(dead_code)] - fn with_foreign_items(mut self, items: I) -> Self - where I: IntoIterator, - { - self.inner.items.extend(items.into_iter()); - self - } - - fn build(self, ctx: &BindgenContext) -> P { - use syntax::codemap::DUMMY_SP; - P(ast::Item { - ident: ctx.rust_ident(""), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::ForeignMod(self.inner), - vis: ast::Visibility::Public, - attrs: vec![], - span: DUMMY_SP, - }) - } -} - -/// A trait to convert a rust type into a pointer, optionally const, to the same -/// type. -/// -/// This is done due to aster's lack of pointer builder, I guess I should PR -/// there. -trait ToPtr { - fn to_ptr(self, is_const: bool, span: Span) -> P; -} - -impl ToPtr for P { - fn to_ptr(self, is_const: bool, span: Span) -> Self { - let ty = ast::TyKind::Ptr(ast::MutTy { - ty: self, - mutbl: if is_const { - ast::Mutability::Immutable - } else { - ast::Mutability::Mutable - }, - }); - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: span, - }) - } -} - -trait CodeGenerator { - /// Extra information from the caller. - type Extra; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - extra: &Self::Extra); -} - -impl CodeGenerator for Item { - type Extra = (); - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - _extra: &()) { - if self.is_hidden(ctx) || result.seen(self.id()) { - debug!("::codegen: Ignoring hidden or seen: \ - self = {:?}", - self); - return; - } - - debug!("::codegen: self = {:?}", self); - if !whitelisted_items.contains(&self.id()) { - // TODO(emilio, #453): Figure out what to do when this happens - // legitimately, we could track the opaque stuff and disable the - // assertion there I guess. - error!("Found non-whitelisted item in code generation: {:?}", self); - } - - result.set_seen(self.id()); - - match *self.kind() { - ItemKind::Module(ref module) => { - module.codegen(ctx, result, whitelisted_items, self); - } - ItemKind::Function(ref fun) => { - if ctx.options().codegen_config.functions { - fun.codegen(ctx, result, whitelisted_items, self); - } - } - ItemKind::Var(ref var) => { - if ctx.options().codegen_config.vars { - var.codegen(ctx, result, whitelisted_items, self); - } - } - ItemKind::Type(ref ty) => { - if ctx.options().codegen_config.types { - ty.codegen(ctx, result, whitelisted_items, self); - } - } - } - } -} - -impl CodeGenerator for Module { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let codegen_self = |result: &mut CodegenResult, - found_any: &mut bool| { - for child in self.children() { - if whitelisted_items.contains(child) { - *found_any = true; - ctx.resolve_item(*child) - .codegen(ctx, result, whitelisted_items, &()); - } - } - - if item.id() == ctx.root_module() { - if result.saw_union && !ctx.options().unstable_rust { - utils::prepend_union_types(ctx, &mut *result); - } - if result.saw_incomplete_array { - utils::prepend_incomplete_array_types(ctx, &mut *result); - } - if ctx.need_bindegen_complex_type() { - utils::prepend_complex_type(ctx, &mut *result); - } - if result.saw_objc { - utils::prepend_objc_header(ctx, &mut *result); - } - } - }; - - if !ctx.options().enable_cxx_namespaces || - (self.is_inline() && !ctx.options().conservative_inline_namespaces) { - codegen_self(result, &mut false); - return; - } - - let mut found_any = false; - let inner_items = result.inner(|result| { - result.push(root_import(ctx, item)); - codegen_self(result, &mut found_any); - }); - - // Don't bother creating an empty module. - if !found_any { - return; - } - - let module = ast::ItemKind::Mod(ast::Mod { - inner: ctx.span(), - items: inner_items, - }); - - let name = item.canonical_name(ctx); - let item_builder = aster::AstBuilder::new() - .item() - .pub_(); - let item = if name == "root" { - let attrs = &["non_snake_case", - "non_camel_case_types", - "non_upper_case_globals"]; - item_builder.with_attr(attributes::allow(attrs)) - .build_item_kind(name, module) - } else { - item_builder.build_item_kind(name, module) - }; - - result.push(item); - } -} - -impl CodeGenerator for Var { - type Extra = Item; - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - use ir::var::VarType; - debug!("::codegen: item = {:?}", item); - - let canonical_name = item.canonical_name(ctx); - - if result.seen_var(&canonical_name) { - return; - } - result.saw_var(&canonical_name); - - let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); - - if let Some(val) = self.val() { - let const_item = aster::AstBuilder::new() - .item() - .pub_() - .const_(canonical_name) - .expr(); - let item = match *val { - VarType::Bool(val) => { - const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) - } - VarType::Int(val) => { - const_item.build(helpers::ast_ty::int_expr(val)).build(ty) - } - VarType::String(ref bytes) => { - // Account the trailing zero. - // - // TODO: Here we ignore the type we just made up, probably - // we should refactor how the variable type and ty id work. - let len = bytes.len() + 1; - let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); - - match String::from_utf8(bytes.clone()) { - Ok(string) => { - const_item.build(helpers::ast_ty::cstr_expr(string)) - .build(quote_ty!(ctx.ext_cx(), &'static $ty)) - } - Err(..) => { - const_item - .build(helpers::ast_ty::byte_array_expr(bytes)) - .build(ty) - } - } - } - VarType::Float(f) => { - match helpers::ast_ty::float_expr(ctx, f) { - Ok(expr) => { - const_item.build(expr).build(ty) - } - Err(..) => return, - } - } - VarType::Char(c) => { - const_item - .build(aster::AstBuilder::new().expr().lit().byte(c)) - .build(ty) - } - }; - - result.push(item); - } else { - let mut attrs = vec![]; - if let Some(mangled) = self.mangled_name() { - attrs.push(attributes::link_name(mangled)); - } else if canonical_name != self.name() { - attrs.push(attributes::link_name(self.name())); - } - - let item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attrs, - node: ast::ForeignItemKind::Static(ty, !self.is_const()), - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, - }; - - let item = ForeignModBuilder::new(Abi::C) - .with_foreign_item(item) - .build(ctx); - result.push(item); - } - } -} - -impl CodeGenerator for Type { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - match *self.kind() { - TypeKind::Void | - TypeKind::NullPtr | - TypeKind::Int(..) | - TypeKind::Float(..) | - TypeKind::Complex(..) | - TypeKind::Array(..) | - TypeKind::Pointer(..) | - TypeKind::BlockPointer | - TypeKind::Reference(..) | - TypeKind::Function(..) | - TypeKind::ResolvedTypeRef(..) | - TypeKind::Opaque | - TypeKind::Named => { - // These items don't need code generation, they only need to be - // converted to rust types in fields, arguments, and such. - return; - } - TypeKind::TemplateInstantiation(ref inst) => { - inst.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::Comp(ref ci) => { - ci.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::TemplateAlias(inner, _) | - TypeKind::Alias(inner) => { - let inner_item = ctx.resolve_item(inner); - let name = item.canonical_name(ctx); - - // Try to catch the common pattern: - // - // typedef struct foo { ... } foo; - // - // here. - // - if inner_item.canonical_name(ctx) == name { - return; - } - - // If this is a known named type, disallow generating anything - // for it too. - let spelling = self.name().expect("Unnamed alias?"); - if utils::type_from_named(ctx, spelling, inner).is_some() { - return; - } - - let mut used_template_params = item.used_template_params(ctx); - let inner_rust_type = if item.is_opaque(ctx) { - used_template_params = None; - self.to_opaque(ctx, item) - } else { - // Its possible that we have better layout information than - // the inner type does, so fall back to an opaque blob based - // on our layout if converting the inner item fails. - inner_item.try_to_rust_ty_or_opaque(ctx, &()) - .unwrap_or_else(|_| self.to_opaque(ctx, item)) - }; - - { - // FIXME(emilio): This is a workaround to avoid generating - // incorrect type aliases because of types that we haven't - // been able to resolve (because, eg, they depend on a - // template parameter). - // - // It's kind of a shame not generating them even when they - // could be referenced, but we already do the same for items - // with invalid template parameters, and at least this way - // they can be replaced, instead of generating plain invalid - // code. - let inner_canon_type = inner_item.expect_type() - .canonical_type(ctx); - if inner_canon_type.is_invalid_named_type() { - warn!("Item contained invalid named type, skipping: \ - {:?}, {:?}", - item, - inner_item); - return; - } - } - - let rust_name = ctx.rust_ident(&name); - let mut typedef = aster::AstBuilder::new().item().pub_(); - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - typedef = typedef.attr().doc(comment); - } - } - - // We prefer using `pub use` over `pub type` because of: - // https://github.com/rust-lang/rust/issues/26264 - let simple_enum_path = match inner_rust_type.node { - ast::TyKind::Path(None, ref p) => { - if used_template_params.is_none() && - inner_item.expect_type() - .canonical_type(ctx) - .is_enum() && - p.segments.iter().all(|p| p.parameters.is_none()) { - Some(p.clone()) - } else { - None - } - } - _ => None, - }; - - let typedef = if let Some(mut p) = simple_enum_path { - for ident in top_level_path(ctx, item).into_iter().rev() { - p.segments.insert(0, - ast::PathSegment { - identifier: ident, - parameters: None, - }); - } - typedef.use_().build(p).as_(rust_name) - } else { - let mut generics = typedef.type_(rust_name).generics(); - if let Some(ref params) = used_template_params { - for template_param in params { - if let Some(id) = - template_param.as_named(ctx, &()) { - let template_param = ctx.resolve_type(id); - if template_param.is_invalid_named_type() { - warn!("Item contained invalid template \ - parameter: {:?}", - item); - return; - } - generics = - generics.ty_param_id(template_param.name() - .unwrap()); - } - } - } - generics.build().build_ty(inner_rust_type) - }; - result.push(typedef) - } - TypeKind::Enum(ref ei) => { - ei.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::ObjCId | TypeKind::ObjCSel => { - result.saw_objc(); - } - TypeKind::ObjCInterface(ref interface) => { - interface.codegen(ctx, result, whitelisted_items, item) - } - ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) - } - } - } -} - -struct Vtable<'a> { - item_id: ItemId, - #[allow(dead_code)] - methods: &'a [Method], - #[allow(dead_code)] - base_classes: &'a [Base], -} - -impl<'a> Vtable<'a> { - fn new(item_id: ItemId, - methods: &'a [Method], - base_classes: &'a [Base]) - -> Self { - Vtable { - item_id: item_id, - methods: methods, - base_classes: base_classes, - } - } -} - -impl<'a> CodeGenerator for Vtable<'a> { - type Extra = Item; - - fn codegen<'b>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'b>, - _whitelisted_items: &ItemSet, - item: &Item) { - assert_eq!(item.id(), self.item_id); - // For now, generate an empty struct, later we should generate function - // pointers and whatnot. - let attributes = vec![attributes::repr("C")]; - - let vtable = aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .tuple_struct(self.canonical_name(ctx)) - .field() - .build_ty(helpers::ast_ty::raw_type(ctx, "c_void")) - .build(); - result.push(vtable); - } -} - -impl<'a> ItemCanonicalName for Vtable<'a> { - fn canonical_name(&self, ctx: &BindgenContext) -> String { - format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) - } -} - -impl<'a> TryToRustTy for Vtable<'a> { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) -> error::Result> { - Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) - } -} - -struct Bitfield<'a> { - index: &'a mut usize, - fields: Vec<&'a Field>, -} - -impl<'a> Bitfield<'a> { - fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self { - Bitfield { - index: index, - fields: fields, - } - } - - fn codegen_fields(self, - ctx: &BindgenContext, - parent: &CompInfo, - fields: &mut Vec, - methods: &mut Vec) - -> Layout { - // NOTE: What follows is reverse-engineered from LLVM's - // lib/AST/RecordLayoutBuilder.cpp - // - // FIXME(emilio): There are some differences between Microsoft and the - // Itanium ABI, but we'll ignore those and stick to Itanium for now. - // - // Also, we need to handle packed bitfields and stuff. - // TODO(emilio): Take into account C++'s wide bitfields, and - // packing, sigh. - let mut total_size_in_bits = 0; - let mut max_align = 0; - let mut unfilled_bits_in_last_unit = 0; - let mut field_size_in_bits = 0; - *self.index += 1; - let mut last_field_name = format!("_bitfield_{}", self.index); - let mut last_field_align = 0; - - // (name, mask, width, bitfield's type, bitfield's layout) - let mut bitfields: Vec<(&str, usize, usize, ast::Ty, Layout)> = vec![]; - - for field in self.fields { - let width = field.bitfield().unwrap() as usize; - let field_item = ctx.resolve_item(field.ty()); - let field_ty_layout = field_item.kind() - .expect_type() - .layout(ctx) - .expect("Bitfield without layout? Gah!"); - let field_align = field_ty_layout.align; - - if field_size_in_bits != 0 && - (width == 0 || width > unfilled_bits_in_last_unit) { - // We've finished a physical field, so flush it and its bitfields. - field_size_in_bits = align_to(field_size_in_bits, field_align); - fields.push(flush_bitfields(ctx, - parent, - field_size_in_bits, - last_field_align, - &last_field_name, - bitfields.drain(..), - methods)); - - // TODO(emilio): dedup this. - *self.index += 1; - last_field_name = format!("_bitfield_{}", self.index); - - // Now reset the size and the rest of stuff. - // unfilled_bits_in_last_unit = 0; - field_size_in_bits = 0; - last_field_align = 0; - } - - if let Some(name) = field.name() { - let field_item_ty = field_item.to_rust_ty_or_opaque(ctx, &()); - bitfields.push((name, - field_size_in_bits, - width, - field_item_ty.unwrap(), - field_ty_layout)); - } - - field_size_in_bits += width; - total_size_in_bits += width; - - let data_size = align_to(field_size_in_bits, field_align * 8); - - max_align = cmp::max(max_align, field_align); - - // NB: The width here is completely, absolutely intentional. - last_field_align = cmp::max(last_field_align, width); - - unfilled_bits_in_last_unit = data_size - field_size_in_bits; - } - - if field_size_in_bits != 0 { - // Flush the last physical field and its bitfields. - fields.push(flush_bitfields(ctx, - parent, - field_size_in_bits, - last_field_align, - &last_field_name, - bitfields.drain(..), - methods)); - } - - Layout::new(bytes_from_bits(total_size_in_bits), max_align) - } -} - -fn parent_has_method(ctx: &BindgenContext, - parent: &CompInfo, - name: &str) - -> bool { - parent.methods().iter().any(|method| { - let method_name = match *ctx.resolve_item(method.signature()).kind() { - ItemKind::Function(ref func) => func.name(), - ref otherwise => panic!("a method's signature should always be a \ - item of kind ItemKind::Function, found: \ - {:?}", - otherwise), - }; - - method_name == name || ctx.rust_mangle(&method_name) == name - }) -} - -fn bitfield_getter_name(ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str) - -> ast::Ident { - let name = ctx.rust_mangle(bitfield_name); - - if parent_has_method(ctx, parent, &name) { - let mut name = name.to_string(); - name.push_str("_bindgen_bitfield"); - return ctx.ext_cx().ident_of(&name); - } - - ctx.ext_cx().ident_of(&name) -} - -fn bitfield_setter_name(ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str) - -> ast::Ident { - let setter = format!("set_{}", bitfield_name); - let mut setter = ctx.rust_mangle(&setter).to_string(); - - if parent_has_method(ctx, parent, &setter) { - setter.push_str("_bindgen_bitfield"); - } - - ctx.ext_cx().ident_of(&setter) -} - -/// A physical field (which is a word or byte or ...) has many logical bitfields -/// contained within it, but not all bitfields are in the same physical field of -/// a struct. This function creates a single physical field and flushes all the -/// accessors for the logical `bitfields` within that physical field to the -/// outgoing `methods`. -fn flush_bitfields<'a, I>(ctx: &BindgenContext, - parent: &CompInfo, - field_size_in_bits: usize, - field_align: usize, - field_name: &str, - bitfields: I, - methods: &mut Vec) -> ast::StructField - where I: IntoIterator -{ - use aster::struct_field::StructFieldBuilder; - - let field_layout = Layout::new(bytes_from_bits_pow2(field_size_in_bits), - bytes_from_bits_pow2(field_align)); - let field_ty = BlobTyBuilder::new(field_layout).build(); - - let field = StructFieldBuilder::named(field_name) - .pub_() - .build_ty(field_ty.clone()); - - let field_int_ty = match field_layout.size { - 8 => quote_ty!(ctx.ext_cx(), u64), - 4 => quote_ty!(ctx.ext_cx(), u32), - 2 => quote_ty!(ctx.ext_cx(), u16), - 1 => quote_ty!(ctx.ext_cx(), u8), - _ => return field - }; - - for (name, offset, width, bitfield_ty, bitfield_layout) in bitfields { - let prefix = ctx.trait_prefix(); - let getter_name = bitfield_getter_name(ctx, parent, name); - let setter_name = bitfield_setter_name(ctx, parent, name); - let field_ident = ctx.ext_cx().ident_of(field_name); - - let bitfield_int_ty = BlobTyBuilder::new(bitfield_layout).build(); - - let mask: usize = ((1usize << width) - 1usize) << offset; - - let impl_item = quote_item!( - ctx.ext_cx(), - impl XxxIgnored { - #[inline] - pub fn $getter_name(&self) -> $bitfield_ty { - let mask = $mask as $field_int_ty; - let field_val: $field_int_ty = unsafe { - ::$prefix::mem::transmute(self.$field_ident) - }; - let val = (field_val & mask) >> $offset; - unsafe { - ::$prefix::mem::transmute(val as $bitfield_int_ty) - } - } - - #[inline] - pub fn $setter_name(&mut self, val: $bitfield_ty) { - let mask = $mask as $field_int_ty; - let val = val as $bitfield_int_ty as $field_int_ty; - - let mut field_val: $field_int_ty = unsafe { - ::$prefix::mem::transmute(self.$field_ident) - }; - field_val &= !mask; - field_val |= (val << $offset) & mask; - - self.$field_ident = unsafe { - ::$prefix::mem::transmute(field_val) - }; - } - } - ).unwrap(); - - match impl_item.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, items) => { - methods.extend(items.into_iter()); - }, - _ => unreachable!(), - }; - } - - field -} - -impl CodeGenerator for TemplateInstantiation { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - // Although uses of instantiations don't need code generation, and are - // just converted to rust types in fields, vars, etc, we take this - // opportunity to generate tests for their layout here. - if !ctx.options().layout_tests { - return - } - - let layout = item.kind().expect_type().layout(ctx); - - if let Some(layout) = layout { - let size = layout.size; - let align = layout.align; - - let name = item.canonical_name(ctx); - let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", - name, - item.id().as_usize()); - let fn_name = ctx.rust_ident_raw(&fn_name); - - let prefix = ctx.trait_prefix(); - let ident = item.to_rust_ty_or_opaque(ctx, &()); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$ident>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$ident>()); - - let item = quote_item!( - ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size, - concat!("Size of template specialization: ", stringify!($ident))); - assert_eq!($align_of_expr, $align, - concat!("Alignment of template specialization: ", stringify!($ident))); - }) - .unwrap(); - - result.push(item); - } - } -} - -impl CodeGenerator for CompInfo { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - use aster::struct_field::StructFieldBuilder; - - debug!("::codegen: item = {:?}", item); - - // Don't output classes with template parameters that aren't types, and - // also don't output template specializations, neither total or partial. - if self.has_non_type_template_params() { - return; - } - - let used_template_params = item.used_template_params(ctx); - - // generate tuple struct if struct or union is a forward declaration, - // skip for now if template parameters are needed. - if self.is_forward_declaration() && used_template_params.is_none() { - let struct_name = item.canonical_name(ctx); - let struct_name = ctx.rust_ident_raw(&struct_name); - let tuple_struct = quote_item!(ctx.ext_cx(), - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct $struct_name([u8; 0]); - ) - .unwrap(); - result.push(tuple_struct); - return; - } - - let mut attributes = vec![]; - let mut needs_clone_impl = false; - let mut needs_default_impl = false; - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - attributes.push(attributes::doc(comment)); - } - } - if self.packed() { - attributes.push(attributes::repr_list(&["C", "packed"])); - } else { - attributes.push(attributes::repr("C")); - } - - let is_union = self.kind() == CompKind::Union; - let mut derives = vec![]; - if item.can_derive_debug(ctx, ()) { - derives.push("Debug"); - } - - if item.can_derive_default(ctx, ()) { - derives.push("Default"); - } else { - needs_default_impl = ctx.options().derive_default; - } - - if item.can_derive_copy(ctx, ()) && - !item.annotations().disallow_copy() { - derives.push("Copy"); - if used_template_params.is_some() { - // FIXME: This requires extra logic if you have a big array in a - // templated struct. The reason for this is that the magic: - // fn clone(&self) -> Self { *self } - // doesn't work for templates. - // - // It's not hard to fix though. - derives.push("Clone"); - } else { - needs_clone_impl = true; - } - } - - if !derives.is_empty() { - attributes.push(attributes::derives(&derives)) - } - - let canonical_name = item.canonical_name(ctx); - let builder = if is_union && ctx.options().unstable_rust { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .union_(&canonical_name) - } else { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .struct_(&canonical_name) - }; - - // Generate the vtable from the method list if appropriate. - // - // TODO: I don't know how this could play with virtual methods that are - // not in the list of methods found by us, we'll see. Also, could the - // order of the vtable pointers vary? - // - // FIXME: Once we generate proper vtables, we need to codegen the - // vtable, but *not* generate a field for it in the case that - // needs_explicit_vtable is false but has_vtable is true. - // - // Also, we need to generate the vtable in such a way it "inherits" from - // the parent too. - let mut fields = vec![]; - let mut struct_layout = StructLayoutTracker::new(ctx, self); - if self.needs_explicit_vtable(ctx) { - let vtable = - Vtable::new(item.id(), self.methods(), self.base_members()); - vtable.codegen(ctx, result, whitelisted_items, item); - - let vtable_type = vtable.try_to_rust_ty(ctx, &()) - .expect("vtable to Rust type conversion is infallible") - .to_ptr(true, ctx.span()); - - let vtable_field = StructFieldBuilder::named("vtable_") - .pub_() - .build_ty(vtable_type); - - struct_layout.saw_vtable(); - - fields.push(vtable_field); - } - - for (i, base) in self.base_members().iter().enumerate() { - // Virtual bases are already taken into account by the vtable - // pointer. - // - // FIXME(emilio): Is this always right? - if base.is_virtual() { - continue; - } - - let base_ty = ctx.resolve_type(base.ty); - // NB: We won't include unsized types in our base chain because they - // would contribute to our size given the dummy field we insert for - // unsized types. - if base_ty.is_unsized(ctx) { - continue; - } - - let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); - let field_name = if i == 0 { - "_base".into() - } else { - format!("_base_{}", i) - }; - - struct_layout.saw_base(base_ty); - - let field = StructFieldBuilder::named(field_name) - .pub_() - .build_ty(inner); - fields.push(field); - } - if is_union { - result.saw_union(); - } - - let layout = item.kind().expect_type().layout(ctx); - - let mut current_bitfield_width = None; - let mut current_bitfield_layout: Option = None; - let mut current_bitfield_fields = vec![]; - let mut bitfield_count = 0; - let struct_fields = self.fields(); - let fields_should_be_private = item.annotations() - .private_fields() - .unwrap_or(false); - let struct_accessor_kind = item.annotations() - .accessor_kind() - .unwrap_or(FieldAccessorKind::None); - - let mut methods = vec![]; - let mut anonymous_field_count = 0; - for field in struct_fields { - debug_assert_eq!(current_bitfield_width.is_some(), - current_bitfield_layout.is_some()); - debug_assert_eq!(current_bitfield_width.is_some(), - !current_bitfield_fields.is_empty()); - - let field_ty = ctx.resolve_type(field.ty()); - - // Try to catch a bitfield contination early. - if let (Some(ref mut bitfield_width), Some(width)) = - (current_bitfield_width, field.bitfield()) { - let layout = current_bitfield_layout.unwrap(); - debug!("Testing bitfield continuation {} {} {:?}", - *bitfield_width, - width, - layout); - if *bitfield_width + width <= (layout.size * 8) as u32 { - *bitfield_width += width; - current_bitfield_fields.push(field); - continue; - } - } - - // Flush the current bitfield. - if current_bitfield_width.is_some() { - debug_assert!(!current_bitfield_fields.is_empty()); - let bitfield_fields = - mem::replace(&mut current_bitfield_fields, vec![]); - let bitfield_layout = Bitfield::new(&mut bitfield_count, - bitfield_fields) - .codegen_fields(ctx, self, &mut fields, &mut methods); - struct_layout.saw_bitfield_batch(bitfield_layout); - - current_bitfield_width = None; - current_bitfield_layout = None; - } - debug_assert!(current_bitfield_fields.is_empty()); - - if let Some(width) = field.bitfield() { - let layout = field_ty.layout(ctx) - .expect("Bitfield type without layout?"); - current_bitfield_width = Some(width); - current_bitfield_layout = Some(layout); - current_bitfield_fields.push(field); - continue; - } - - let ty = field.ty().to_rust_ty_or_opaque(ctx, &()); - - // NB: In unstable rust we use proper `union` types. - let ty = if is_union && !ctx.options().unstable_rust { - if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) - } else { - quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) - } - } else if let Some(item) = - field_ty.is_incomplete_array(ctx) { - result.saw_incomplete_array(); - - let inner = item.to_rust_ty_or_opaque(ctx, &()); - - if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) - } else { - quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) - } - } else { - ty - }; - - let mut attrs = vec![]; - if ctx.options().generate_comments { - if let Some(comment) = field.comment() { - attrs.push(attributes::doc(comment)); - } - } - let field_name = match field.name() { - Some(name) => ctx.rust_mangle(name).into_owned(), - None => { - anonymous_field_count += 1; - format!("__bindgen_anon_{}", anonymous_field_count) - } - }; - - if !is_union { - if let Some(padding_field) = - struct_layout.pad_field(&field_name, field_ty, field.offset()) { - fields.push(padding_field); - } - } - - let is_private = field.annotations() - .private_fields() - .unwrap_or(fields_should_be_private); - - let accessor_kind = field.annotations() - .accessor_kind() - .unwrap_or(struct_accessor_kind); - - let mut field = StructFieldBuilder::named(&field_name); - - if !is_private { - field = field.pub_(); - } - - let field = field.with_attrs(attrs) - .build_ty(ty.clone()); - - fields.push(field); - - // TODO: Factor the following code out, please! - if accessor_kind == FieldAccessorKind::None { - continue; - } - - let getter_name = - ctx.rust_ident_raw(&format!("get_{}", field_name)); - let mutable_getter_name = - ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); - let field_name = ctx.rust_ident_raw(&field_name); - - let accessor_methods_impl = match accessor_kind { - FieldAccessorKind::None => unreachable!(), - FieldAccessorKind::Regular => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } - - #[inline] - pub fn $mutable_getter_name(&mut self) -> &mut $ty { - &mut self.$field_name - } - } - ) - } - FieldAccessorKind::Unsafe => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub unsafe fn $getter_name(&self) -> &$ty { - &self.$field_name - } - - #[inline] - pub unsafe fn $mutable_getter_name(&mut self) - -> &mut $ty { - &mut self.$field_name - } - } - ) - } - FieldAccessorKind::Immutable => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } - } - ) - } - }; - - match accessor_methods_impl.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => { - methods.extend(items.clone()) - } - _ => unreachable!(), - } - } - - // Flush the last bitfield if any. - // - // FIXME: Reduce duplication with the loop above. - // FIXME: May need to pass current_bitfield_layout too. - if current_bitfield_width.is_some() { - debug_assert!(!current_bitfield_fields.is_empty()); - let bitfield_fields = mem::replace(&mut current_bitfield_fields, - vec![]); - let bitfield_layout = Bitfield::new(&mut bitfield_count, - bitfield_fields) - .codegen_fields(ctx, self, &mut fields, &mut methods); - struct_layout.saw_bitfield_batch(bitfield_layout); - } - debug_assert!(current_bitfield_fields.is_empty()); - - if is_union && !ctx.options().unstable_rust { - let layout = layout.expect("Unable to get layout information?"); - let ty = BlobTyBuilder::new(layout).build(); - let field = StructFieldBuilder::named("bindgen_union_field") - .pub_() - .build_ty(ty); - - struct_layout.saw_union(layout); - - fields.push(field); - } - - // Yeah, sorry about that. - if item.is_opaque(ctx) { - fields.clear(); - methods.clear(); - - match layout { - Some(l) => { - let ty = BlobTyBuilder::new(l).build(); - let field = - StructFieldBuilder::named("_bindgen_opaque_blob") - .pub_() - .build_ty(ty); - fields.push(field); - } - None => { - warn!("Opaque type without layout! Expect dragons!"); - } - } - } else if !is_union && !self.is_unsized(ctx) { - if let Some(padding_field) = - layout.and_then(|layout| { - struct_layout.pad_struct(&canonical_name, layout) - }) { - fields.push(padding_field); - } - - if let Some(align_field) = - layout.and_then(|layout| struct_layout.align_struct(layout)) { - fields.push(align_field); - } - } - - // C++ requires every struct to be addressable, so what C++ compilers do - // is making the struct 1-byte sized. - // - // This is apparently not the case for C, see: - // https://github.com/servo/rust-bindgen/issues/551 - // - // Just get the layout, and assume C++ if not. - // - // NOTE: This check is conveniently here to avoid the dummy fields we - // may add for unused template parameters. - if self.is_unsized(ctx) { - let has_address = layout.map_or(true, |l| l.size != 0); - if has_address { - let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); - let field = StructFieldBuilder::named("_address") - .pub_() - .build_ty(ty); - fields.push(field); - } - } - - let mut generics = aster::AstBuilder::new().generics(); - - if let Some(ref params) = used_template_params { - for (idx, ty) in params.iter().enumerate() { - let param = ctx.resolve_type(*ty); - let name = param.name().unwrap(); - let ident = ctx.rust_ident(name); - - generics = generics.ty_param_id(ident); - - let prefix = ctx.trait_prefix(); - let phantom_ty = quote_ty!( - ctx.ext_cx(), - ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); - let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) - .build_ty(phantom_ty); - fields.push(phantom_field); - } - } - - let generics = generics.build(); - - let rust_struct = builder.with_generics(generics.clone()) - .with_fields(fields) - .build(); - result.push(rust_struct); - - // Generate the inner types and all that stuff. - // - // TODO: In the future we might want to be smart, and use nested - // modules, and whatnot. - for ty in self.inner_types() { - let child_item = ctx.resolve_item(*ty); - // assert_eq!(child_item.parent_id(), item.id()); - child_item.codegen(ctx, result, whitelisted_items, &()); - } - - // NOTE: Some unexposed attributes (like alignment attributes) may - // affect layout, so we're bad and pray to the gods for avoid sending - // all the tests to shit when parsing things like max_align_t. - if self.found_unknown_attr() { - warn!("Type {} has an unkown attribute that may affect layout", - canonical_name); - } - - if used_template_params.is_none() { - for var in self.inner_vars() { - ctx.resolve_item(*var) - .codegen(ctx, result, whitelisted_items, &()); - } - - if ctx.options().layout_tests { - if let Some(layout) = layout { - let fn_name = format!("bindgen_test_layout_{}", canonical_name); - let fn_name = ctx.rust_ident_raw(&fn_name); - let type_name = ctx.rust_ident_raw(&canonical_name); - let prefix = ctx.trait_prefix(); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$type_name>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$type_name>()); - let size = layout.size; - let align = layout.align; - - let check_struct_align = if align > mem::size_of::<*mut ()>() { - // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready - None - } else { - quote_item!(ctx.ext_cx(), - assert_eq!($align_of_expr, - $align, - concat!("Alignment of ", stringify!($type_name))); - ) - }; - - // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready - let too_many_base_vtables = self.base_members() - .iter() - .filter(|base| { - ctx.resolve_type(base.ty).has_vtable(ctx) - }) - .count() > 1; - - let should_skip_field_offset_checks = item.is_opaque(ctx) || - too_many_base_vtables; - - let check_field_offset = if should_skip_field_offset_checks { - None - } else { - let asserts = self.fields() - .iter() - .filter(|field| field.bitfield().is_none()) - .flat_map(|field| { - field.name().and_then(|name| { - field.offset().and_then(|offset| { - let field_offset = offset / 8; - let field_name = ctx.rust_ident(name); - - quote_item!(ctx.ext_cx(), - assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, - $field_offset, - concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); - ) - }) - }) - }).collect::>>(); - - Some(asserts) - }; - - let item = quote_item!(ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, - $size, - concat!("Size of: ", stringify!($type_name))); - - $check_struct_align - $check_field_offset - }) - .unwrap(); - result.push(item); - } - } - - let mut method_names = Default::default(); - if ctx.options().codegen_config.methods { - for method in self.methods() { - assert!(method.kind() != MethodKind::Constructor); - method.codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - - if ctx.options().codegen_config.constructors { - for sig in self.constructors() { - Method::new(MethodKind::Constructor, - *sig, - /* const */ - false) - .codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - - if ctx.options().codegen_config.destructors { - if let Some((is_virtual, destructor)) = self.destructor() { - let kind = if is_virtual { - MethodKind::VirtualDestructor - } else { - MethodKind::Destructor - }; - - Method::new(kind, destructor, false) - .codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - } - - // NB: We can't use to_rust_ty here since for opaque types this tries to - // use the specialization knowledge to generate a blob field. - let ty_for_impl = aster::AstBuilder::new() - .ty() - .path() - .segment(&canonical_name) - .with_generics(generics.clone()) - .build() - .build(); - - if needs_clone_impl { - let impl_ = quote_item!(ctx.ext_cx(), - impl X { - fn clone(&self) -> Self { *self } - } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let clone_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Clone") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(clone_impl); - } - - if needs_default_impl { - let prefix = ctx.trait_prefix(); - let impl_ = quote_item!(ctx.ext_cx(), - impl X { - fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } - } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let default_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Default") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(default_impl); - } - - if !methods.is_empty() { - let methods = aster::AstBuilder::new() - .item() - .impl_() - .with_generics(generics) - .with_items(methods) - .build_ty(ty_for_impl); - result.push(methods); - } - } -} - -trait MethodCodegen { - fn codegen_method<'a>(&self, - ctx: &BindgenContext, - methods: &mut Vec, - method_names: &mut HashMap, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - parent: &CompInfo); -} - -impl MethodCodegen for Method { - fn codegen_method<'a>(&self, - ctx: &BindgenContext, - methods: &mut Vec, - method_names: &mut HashMap, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - _parent: &CompInfo) { - if self.is_virtual() { - return; // FIXME - } - - // First of all, output the actual function. - let function_item = ctx.resolve_item(self.signature()); - function_item.codegen(ctx, result, whitelisted_items, &()); - - let function = function_item.expect_function(); - let signature_item = ctx.resolve_item(function.signature()); - let mut name = match self.kind() { - MethodKind::Constructor => "new".into(), - MethodKind::Destructor => "destruct".into(), - _ => function.name().to_owned(), - }; - - let signature = match *signature_item.expect_type().kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How in the world?"), - }; - - // Do not generate variadic methods, since rust does not allow - // implementing them, and we don't do a good job at it anyway. - if signature.is_variadic() { - return; - } - - let count = { - let mut count = method_names.entry(name.clone()) - .or_insert(0); - *count += 1; - *count - 1 - }; - - if count != 0 { - name.push_str(&count.to_string()); - } - - let function_name = function_item.canonical_name(ctx); - let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) - .unwrap(); - if !self.is_static() && !self.is_constructor() { - let mutability = if self.is_const() { - ast::Mutability::Immutable - } else { - ast::Mutability::Mutable - }; - - assert!(!fndecl.inputs.is_empty()); - - // FIXME: use aster here. - fndecl.inputs[0] = ast::Arg { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Rptr(None, ast::MutTy { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::ImplicitSelf, - span: ctx.span() - }), - mutbl: mutability, - }), - span: ctx.span(), - }), - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident( - ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span(), ctx.ext_cx().ident_of("self")), - None - ), - span: ctx.span(), - }), - id: ast::DUMMY_NODE_ID, - }; - } - - // If it's a constructor, we always return `Self`, and we inject the - // "this" parameter, so there's no need to ask the user for it. - // - // Note that constructors in Clang are represented as functions with - // return-type = void. - if self.is_constructor() { - fndecl.inputs.remove(0); - fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), - Self)); - } - - let sig = ast::MethodSig { - unsafety: ast::Unsafety::Unsafe, - abi: Abi::Rust, - decl: P(fndecl), - generics: ast::Generics::default(), - constness: respan(ctx.span(), ast::Constness::NotConst), - }; - - let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, - ctx); - - let mut stmts = vec![]; - - // If it's a constructor, we need to insert an extra parameter with a - // variable called `__bindgen_tmp` we're going to create. - if self.is_constructor() { - let prefix = ctx.trait_prefix(); - let tmp_variable_decl = - quote_stmt!(ctx.ext_cx(), - let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) - .unwrap(); - stmts.push(tmp_variable_decl); - exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); - } else if !self.is_static() { - assert!(!exprs.is_empty()); - exprs[0] = quote_expr!(ctx.ext_cx(), self); - }; - - let call = aster::expr::ExprBuilder::new() - .call() - .id(function_name) - .with_args(exprs) - .build(); - - stmts.push(ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(call), - span: ctx.span(), - }); - - if self.is_constructor() { - stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); - } - - let block = ast::Block { - stmts: stmts, - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), - }; - - let mut attrs = vec![]; - attrs.push(attributes::inline()); - - let item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(&name), - vis: ast::Visibility::Public, - attrs: attrs, - node: ast::ImplItemKind::Method(sig, P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), - }; - - methods.push(item); - } -} - -/// A helper type to construct enums, either bitfield ones or rust-style ones. -enum EnumBuilder<'a> { - Rust(aster::item::ItemEnumBuilder), - Bitfield { - canonical_name: &'a str, - aster: P, - }, - Consts { aster: P }, -} - -impl<'a> EnumBuilder<'a> { - /// Create a new enum given an item builder, a canonical name, a name for - /// the representation, and whether it should be represented as a rust enum. - fn new(aster: aster::item::ItemBuilder, - name: &'a str, - repr: P, - bitfield_like: bool, - constify: bool) - -> Self { - if bitfield_like { - EnumBuilder::Bitfield { - canonical_name: name, - aster: aster.tuple_struct(name) - .field() - .pub_() - .build_ty(repr) - .build(), - } - } else if constify { - EnumBuilder::Consts { - aster: aster.type_(name).build_ty(repr), - } - } else { - EnumBuilder::Rust(aster.enum_(name)) - } - } - - /// Add a variant to this enum. - fn with_variant<'b>(self, - ctx: &BindgenContext, - variant: &EnumVariant, - mangling_prefix: Option<&String>, - rust_ty: P, - result: &mut CodegenResult<'b>) - -> Self { - let variant_name = ctx.rust_mangle(variant.name()); - let expr = aster::AstBuilder::new().expr(); - let expr = match variant.val() { - EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), - EnumVariantValue::Unsigned(v) => expr.uint(v), - }; - - match self { - EnumBuilder::Rust(b) => { - EnumBuilder::Rust(b.with_variant_(ast::Variant_ { - name: ctx.rust_ident(&*variant_name), - attrs: vec![], - data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), - disr_expr: Some(expr), - })) - } - EnumBuilder::Bitfield { canonical_name, .. } => { - let constant_name = match mangling_prefix { - Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) - } - None => variant_name, - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .call() - .id(canonical_name) - .arg() - .build(expr) - .build() - .build(rust_ty); - result.push(constant); - self - } - EnumBuilder::Consts { .. } => { - let constant_name = match mangling_prefix { - Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) - } - None => variant_name, - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .build(expr) - .build(rust_ty); - - result.push(constant); - self - } - } - } - - fn build<'b>(self, - ctx: &BindgenContext, - rust_ty: P, - result: &mut CodegenResult<'b>) - -> P { - match self { - EnumBuilder::Rust(b) => b.build(), - EnumBuilder::Bitfield { canonical_name, aster } => { - let rust_ty_name = ctx.rust_ident_raw(canonical_name); - let prefix = ctx.trait_prefix(); - - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { - type Output = Self; - - #[inline] - fn bitor(self, other: Self) -> Self { - $rust_ty_name(self.0 | other.0) - } - } - ) - .unwrap(); - - result.push(impl_); - aster - } - EnumBuilder::Consts { aster, .. } => aster, - } - } -} - -impl CodeGenerator for Enum { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let name = item.canonical_name(ctx); - let enum_ty = item.expect_type(); - let layout = enum_ty.layout(ctx); - - let repr = self.repr().map(|repr| ctx.resolve_type(repr)); - let repr = match repr { - Some(repr) => { - match *repr.canonical_type(ctx).kind() { - TypeKind::Int(int_kind) => int_kind, - _ => panic!("Unexpected type as enum repr"), - } - } - None => { - warn!("Guessing type of enum! Forward declarations of enums \ - shouldn't be legal!"); - IntKind::Int - } - }; - - let signed = repr.is_signed(); - let size = layout.map(|l| l.size) - .or_else(|| repr.known_size()) - .unwrap_or(0); - - let repr_name = match (signed, size) { - (true, 1) => "i8", - (false, 1) => "u8", - (true, 2) => "i16", - (false, 2) => "u16", - (true, 4) => "i32", - (false, 4) => "u32", - (true, 8) => "i64", - (false, 8) => "u64", - _ => { - warn!("invalid enum decl: signed: {}, size: {}", signed, size); - "i32" - } - }; - - let mut builder = aster::AstBuilder::new().item().pub_(); - - // FIXME(emilio): These should probably use the path so it can - // disambiguate between namespaces, just like is_opaque etc. - let is_bitfield = { - ctx.options().bitfield_enums.matches(&name) || - (enum_ty.name().is_none() && - self.variants() - .iter() - .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) - }; - - let is_constified_enum = { - ctx.options().constified_enums.matches(&name) || - (enum_ty.name().is_none() && - self.variants() - .iter() - .any(|v| ctx.options().constified_enums.matches(&v.name()))) - }; - - let is_rust_enum = !is_bitfield && !is_constified_enum; - - // FIXME: Rust forbids repr with empty enums. Remove this condition when - // this is allowed. - // - // TODO(emilio): Delegate this to the builders? - if is_rust_enum { - if !self.variants().is_empty() { - builder = builder.with_attr(attributes::repr(repr_name)); - } - } else if is_bitfield { - builder = builder.with_attr(attributes::repr("C")); - } - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - builder = builder.with_attr(attributes::doc(comment)); - } - } - - if !is_constified_enum { - let derives = attributes::derives(&["Debug", - "Copy", - "Clone", - "PartialEq", - "Eq", - "Hash"]); - - builder = builder.with_attr(derives); - } - - fn add_constant<'a>(enum_: &Type, - // Only to avoid recomputing every time. - enum_canonical_name: &str, - // May be the same as "variant" if it's because the - // enum is unnamed and we still haven't seen the - // value. - variant_name: &str, - referenced_name: &str, - enum_rust_ty: P, - result: &mut CodegenResult<'a>) { - let constant_name = if enum_.name().is_some() { - format!("{}_{}", enum_canonical_name, variant_name) - } else { - variant_name.into() - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(constant_name) - .expr() - .path() - .ids(&[&*enum_canonical_name, referenced_name]) - .build() - .build(enum_rust_ty); - result.push(constant); - } - - let repr = self.repr() - .and_then(|repr| repr.try_to_rust_ty_or_opaque(ctx, &()).ok()) - .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); - - let mut builder = EnumBuilder::new(builder, - &name, - repr, - is_bitfield, - is_constified_enum); - - // A map where we keep a value -> variant relation. - let mut seen_values = HashMap::<_, String>::new(); - let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); - let is_toplevel = item.is_toplevel(ctx); - - // Used to mangle the constants we generate in the unnamed-enum case. - let parent_canonical_name = if is_toplevel { - None - } else { - Some(item.parent_id().canonical_name(ctx)) - }; - - let constant_mangling_prefix = if ctx.options().prepend_enum_name { - if enum_ty.name().is_none() { - parent_canonical_name.as_ref().map(|n| &*n) - } else { - Some(&name) - } - } else { - None - }; - - // NB: We defer the creation of constified variants, in case we find - // another variant with the same value (which is the common thing to - // do). - let mut constified_variants = VecDeque::new(); - - let mut iter = self.variants().iter().peekable(); - while let Some(variant) = iter.next() - .or_else(|| constified_variants.pop_front()) { - if variant.hidden() { - continue; - } - - if variant.force_constification() && iter.peek().is_some() { - constified_variants.push_back(variant); - continue; - } - - match seen_values.entry(variant.val()) { - Entry::Occupied(ref entry) => { - if is_rust_enum { - let variant_name = ctx.rust_mangle(variant.name()); - let mangled_name = if is_toplevel || - enum_ty.name().is_some() { - variant_name - } else { - let parent_name = parent_canonical_name.as_ref() - .unwrap(); - - Cow::Owned(format!("{}_{}", - parent_name, - variant_name)) - }; - - let existing_variant_name = entry.get(); - add_constant(enum_ty, - &name, - &*mangled_name, - existing_variant_name, - enum_rust_ty.clone(), - result); - } else { - builder = builder.with_variant(ctx, - variant, - constant_mangling_prefix, - enum_rust_ty.clone(), - result); - } - } - Entry::Vacant(entry) => { - builder = builder.with_variant(ctx, - variant, - constant_mangling_prefix, - enum_rust_ty.clone(), - result); - - let variant_name = ctx.rust_mangle(variant.name()); - - // If it's an unnamed enum, or constification is enforced, - // we also generate a constant so it can be properly - // accessed. - if (is_rust_enum && enum_ty.name().is_none()) || - variant.force_constification() { - let mangled_name = if is_toplevel { - variant_name.clone() - } else { - let parent_name = parent_canonical_name.as_ref() - .unwrap(); - - Cow::Owned(format!("{}_{}", - parent_name, - variant_name)) - }; - - add_constant(enum_ty, - &name, - &mangled_name, - &variant_name, - enum_rust_ty.clone(), - result); - } - - entry.insert(variant_name.into_owned()); - } - } - } - - let enum_ = builder.build(ctx, enum_rust_ty, result); - result.push(enum_); - } -} - -/// Fallible conversion to an opaque blob. -/// -/// Implementors of this trait should provide the `try_get_layout` method to -/// fallibly get this thing's layout, which the provided `try_to_opaque` trait -/// method will use to convert the `Layout` into an opaque blob Rust type. -trait TryToOpaque { - type Extra; - - /// Get the layout for this thing, if one is available. - fn try_get_layout(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result; - - /// Do not override this provided trait method. - fn try_to_opaque(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result> { - self.try_get_layout(ctx, extra) - .map(|layout| BlobTyBuilder::new(layout).build()) - } -} - -/// Infallible conversion of an IR thing to an opaque blob. -/// -/// The resulting layout is best effort, and is unfortunately not guaranteed to -/// be correct. When all else fails, we fall back to a single byte layout as a -/// last resort, because C++ does not permit zero-sized types. See the note in -/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits -/// and when each is appropriate. -/// -/// Don't implement this directly. Instead implement `TryToOpaque`, and then -/// leverage the blanket impl for this trait. -trait ToOpaque: TryToOpaque { - fn get_layout(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> Layout { - self.try_get_layout(ctx, extra) - .unwrap_or_else(|_| Layout::for_size(1)) - } - - fn to_opaque(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> P { - let layout = self.get_layout(ctx, extra); - BlobTyBuilder::new(layout).build() - } -} - -impl ToOpaque for T - where T: TryToOpaque -{} - -/// Fallible conversion from an IR thing to an *equivalent* Rust type. -/// -/// If the C/C++ construct represented by the IR thing cannot (currently) be -/// represented in Rust (for example, instantiations of templates with -/// const-value generic parameters) then the impl should return an `Err`. It -/// should *not* attempt to return an opaque blob with the correct size and -/// alignment. That is the responsibility of the `TryToOpaque` trait. -trait TryToRustTy { - type Extra; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result>; -} - -/// Fallible conversion to a Rust type or an opaque blob with the correct size -/// and alignment. -/// -/// Don't implement this directly. Instead implement `TryToRustTy` and -/// `TryToOpaque`, and then leverage the blanket impl for this trait below. -trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { - type Extra; - - fn try_to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &::Extra) - -> error::Result>; -} - -impl TryToRustTyOrOpaque for T - where T: TryToRustTy + TryToOpaque -{ - type Extra = E; - - fn try_to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &E) - -> error::Result> { - self.try_to_rust_ty(ctx, extra) - .or_else(|_| { - if let Ok(layout) = self.try_get_layout(ctx, extra) { - Ok(BlobTyBuilder::new(layout).build()) - } else { - Err(error::Error::NoLayoutForOpaqueBlob) - } - }) - } -} - -/// Infallible conversion to a Rust type, or an opaque blob with a best effort -/// of correct size and alignment. -/// -/// Don't implement this directly. Instead implement `TryToRustTy` and -/// `TryToOpaque`, and then leverage the blanket impl for this trait below. -/// -/// ### Fallible vs. Infallible Conversions to Rust Types -/// -/// When should one use this infallible `ToRustTyOrOpaque` trait versus the -/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait -/// implementations that need to convert another thing into a Rust type or -/// opaque blob in a nested manner should also use fallible trait methods and -/// propagate failure up the stack. Only infallible functions and methods like -/// CodeGenerator implementations should use the infallible -/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely -/// we are to get a usable `Layout` even if we can't generate an equivalent Rust -/// type for a C++ construct. -trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { - type Extra; - - fn to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &::Extra) - -> P; -} - -impl ToRustTyOrOpaque for T - where T: TryToRustTy + ToOpaque -{ - type Extra = E; - - fn to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &E) - -> P { - self.try_to_rust_ty(ctx, extra) - .unwrap_or_else(|_| self.to_opaque(ctx, extra)) - } -} - -impl TryToOpaque for ItemId { - type Extra = (); - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result { - ctx.resolve_item(*self).try_get_layout(ctx, &()) - } -} - -impl TryToRustTy for ItemId { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) - } -} - -impl TryToOpaque for Item { - type Extra = (); - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result { - self.kind().expect_type().try_get_layout(ctx, self) - } -} - -impl TryToRustTy for Item { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - self.kind().expect_type().try_to_rust_ty(ctx, self) - } -} - -impl TryToOpaque for Type { - type Extra = Item; - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &Item) - -> error::Result { - self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) - } -} - -impl TryToRustTy for Type { - type Extra = Item; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - item: &Item) - -> error::Result> { - use self::helpers::ast_ty::*; - - match *self.kind() { - TypeKind::Void => Ok(raw_type(ctx, "c_void")), - // TODO: we should do something smart with nullptr, or maybe *const - // c_void is enough? - TypeKind::NullPtr => { - Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) - } - TypeKind::Int(ik) => { - match ik { - IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), - IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), - IntKind::SChar => Ok(raw_type(ctx, "c_schar")), - IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), - IntKind::Short => Ok(raw_type(ctx, "c_short")), - IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), - IntKind::Int => Ok(raw_type(ctx, "c_int")), - IntKind::UInt => Ok(raw_type(ctx, "c_uint")), - IntKind::Long => Ok(raw_type(ctx, "c_long")), - IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), - IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), - IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), - - IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), - IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), - IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), - IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), - IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), - IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), - IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), - IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), - IntKind::Custom { name, .. } => { - let ident = ctx.rust_ident_raw(name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) - } - // FIXME: This doesn't generate the proper alignment, but we - // can't do better right now. We should be able to use - // i128/u128 when they're available. - IntKind::U128 | IntKind::I128 => { - Ok(aster::ty::TyBuilder::new().array(2).u64()) - } - } - } - TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), - TypeKind::Complex(fk) => { - let float_path = float_kind_rust_type(ctx, fk); - - ctx.generated_bindegen_complex(); - Ok(if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) - } else { - quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) - }) - } - TypeKind::Function(ref fs) => { - // We can't rely on the sizeof(Option>) == - // sizeof(NonZero<_>) optimization with opaque blobs (because - // they aren't NonZero), so don't *ever* use an or_opaque - // variant here. - let ty = fs.try_to_rust_ty(ctx, &())?; - - let prefix = ctx.trait_prefix(); - Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) - } - TypeKind::Array(item, len) => { - let ty = item.try_to_rust_ty(ctx, &())?; - Ok(aster::ty::TyBuilder::new().array(len).build(ty)) - } - TypeKind::Enum(..) => { - let path = item.namespace_aware_canonical_path(ctx); - Ok(aster::AstBuilder::new() - .ty() - .path() - .ids(path) - .build()) - } - TypeKind::TemplateInstantiation(ref inst) => { - inst.try_to_rust_ty(ctx, self) - } - TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), - TypeKind::TemplateAlias(inner, _) | - TypeKind::Alias(inner) => { - let template_params = item.used_template_params(ctx) - .unwrap_or(vec![]) - .into_iter() - .filter(|param| param.is_named(ctx, &())) - .collect::>(); - - let spelling = self.name().expect("Unnamed alias?"); - if item.is_opaque(ctx) && !template_params.is_empty() { - self.try_to_opaque(ctx, item) - } else if let Some(ty) = utils::type_from_named(ctx, - spelling, - inner) { - Ok(ty) - } else { - utils::build_templated_path(item, ctx, template_params) - } - } - TypeKind::Comp(ref info) => { - let template_params = item.used_template_params(ctx); - if info.has_non_type_template_params() || - (item.is_opaque(ctx) && template_params.is_some()) { - return self.try_to_opaque(ctx, item); - } - - let template_params = template_params.unwrap_or(vec![]); - utils::build_templated_path(item, - ctx, - template_params) - } - TypeKind::Opaque => { - self.try_to_opaque(ctx, item) - } - TypeKind::BlockPointer => { - let void = raw_type(ctx, "c_void"); - Ok(void.to_ptr(/* is_const = */ - false, - ctx.span())) - } - TypeKind::Pointer(inner) | - TypeKind::Reference(inner) => { - let inner = ctx.resolve_item(inner); - let inner_ty = inner.expect_type(); - - // Regardless if we can properly represent the inner type, we - // should always generate a proper pointer here, so use - // infallible conversion of the inner type. - let ty = inner.to_rust_ty_or_opaque(ctx, &()); - - // Avoid the first function pointer level, since it's already - // represented in Rust. - if inner_ty.canonical_type(ctx).is_function() { - Ok(ty) - } else { - let is_const = self.is_const() || - inner.expect_type().is_const(); - Ok(ty.to_ptr(is_const, ctx.span())) - } - } - TypeKind::Named => { - let name = item.canonical_name(ctx); - let ident = ctx.rust_ident(&name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) - } - TypeKind::ObjCSel => Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)), - TypeKind::ObjCId | - TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), - ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) - } - } - } -} - -impl TryToOpaque for TemplateInstantiation { - type Extra = Type; - - fn try_get_layout(&self, - ctx: &BindgenContext, - self_ty: &Type) - -> error::Result { - self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) - } -} - -impl TryToRustTy for TemplateInstantiation { - type Extra = Type; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &Type) - -> error::Result> { - let decl = self.template_definition(); - let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); - - let decl_params = match decl.self_template_params(ctx) { - Some(params) => params, - None => { - // This can happen if we generated an opaque type for a partial - // template specialization, and we've hit an instantiation of - // that partial specialization. - extra_assert!(ctx.resolve_type_through_type_refs(decl) - .is_opaque()); - return Err(error::Error::InstantiationOfOpaqueType); - } - }; - - // TODO: If the decl type is a template class/struct - // declaration's member template declaration, it could rely on - // generic template parameters from its outer template - // class/struct. When we emit bindings for it, it could require - // *more* type arguments than we have here, and we will need to - // reconstruct them somehow. We don't have any means of doing - // that reconstruction at this time. - - if let ast::TyKind::Path(_, ref mut path) = ty.node { - let template_args = self.template_arguments() - .iter() - .zip(decl_params.iter()) - // Only pass type arguments for the type parameters that - // the decl uses. - .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) - .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) - .collect::>>()?; - - path.segments.last_mut().unwrap().parameters = if - template_args.is_empty() { - None - } else { - Some(P(ast::PathParameters::AngleBracketed( - ast::AngleBracketedParameterData { - lifetimes: vec![], - types: template_args, - bindings: vec![], - } - ))) - } - } - - Ok(P(ty)) - } -} - -impl TryToRustTy for FunctionSig { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - // TODO: we might want to consider ignoring the reference return value. - let ret = utils::fnsig_return_ty(ctx, &self); - let arguments = utils::fnsig_arguments(ctx, &self); - - let decl = P(ast::FnDecl { - inputs: arguments, - output: ret, - variadic: self.is_variadic(), - }); - - let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: self.abi().expect("Invalid abi for function!"), - lifetimes: vec![], - decl: decl, - })); - - Ok(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: fnty, - span: ctx.span(), - })) - } -} - -impl CodeGenerator for Function { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let name = self.name(); - let mut canonical_name = item.canonical_name(ctx); - let mangled_name = self.mangled_name(); - - { - let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); - - // TODO: Maybe warn here if there's a type/argument mismatch, or - // something? - if result.seen_function(seen_symbol_name) { - return; - } - result.saw_function(seen_symbol_name); - } - - let signature_item = ctx.resolve_item(self.signature()); - let signature = signature_item.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("Signature kind is not a Function: {:?}", signature), - }; - - let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); - - let mut attributes = vec![]; - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - attributes.push(attributes::doc(comment)); - } - } - - if let Some(mangled) = mangled_name { - attributes.push(attributes::link_name(mangled)); - } else if name != canonical_name { - attributes.push(attributes::link_name(name)); - } - - let foreign_item_kind = - ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); - - // Handle overloaded functions by giving each overload its own unique - // suffix. - let times_seen = result.overload_number(&canonical_name); - if times_seen > 0 { - write!(&mut canonical_name, "{}", times_seen).unwrap(); - } - - let foreign_item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attributes, - node: foreign_item_kind, - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, - }; - - let item = ForeignModBuilder::new(signature.abi() - .expect("Invalid abi for function!")) - .with_foreign_item(foreign_item) - .build(ctx); - - result.push(item); - } -} - - -fn objc_method_codegen(ctx: &BindgenContext, - method: &ObjCMethod, - class_name: Option<&str>) - -> (ast::ImplItem, ast::TraitItem) { - let signature = method.signature(); - let fn_args = utils::fnsig_arguments(ctx, signature); - let fn_ret = utils::fnsig_return_ty(ctx, signature); - - let sig = if method.is_class_method() { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .with_args(fn_args.clone()) - .build(fn_ret) - } else { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .self_() - .build(ast::SelfKind::Value(ast::Mutability::Immutable)) - .with_args(fn_args.clone()) - .build(fn_ret) - }; - - // Collect the actual used argument names - let arg_names: Vec<_> = fn_args.iter() - .map(|ref arg| match arg.pat.node { - ast::PatKind::Ident(_, ref spanning, _) => { - spanning.node.name.as_str().to_string() - } - _ => { - panic!("odd argument!"); - } - }) - .collect(); - - let methods_and_args = - ctx.rust_ident(&method.format_method_call(&arg_names)); - - let body = if method.is_class_method() { - let class_name = - class_name.expect("Generating a class method without class name?") - .to_owned(); - let expect_msg = format!("Couldn't find {}", class_name); - quote_stmt!(ctx.ext_cx(), - msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args]) - .unwrap() - } else { - quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap() - }; - let block = ast::Block { - stmts: vec![body], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), - }; - - let attrs = vec![]; - - let impl_item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(method.rust_name()), - vis: ast::Visibility::Inherited, // Public, - attrs: attrs.clone(), - node: ast::ImplItemKind::Method(sig.clone(), P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), - }; - - let trait_item = ast::TraitItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(method.rust_name()), - attrs: attrs, - node: ast::TraitItemKind::Method(sig, None), - span: ctx.span(), - }; - - (impl_item, trait_item) -} - -impl CodeGenerator for ObjCInterface { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - _: &Item) { - let mut impl_items = vec![]; - let mut trait_items = vec![]; - - for method in self.methods() { - let (impl_item, trait_item) = - objc_method_codegen(ctx, method, None); - impl_items.push(impl_item); - trait_items.push(trait_item) - } - - for class_method in self.class_methods() { - let (impl_item, trait_item) = - objc_method_codegen(ctx, class_method, Some(self.name())); - impl_items.push(impl_item); - trait_items.push(trait_item) - } - - let trait_name = self.rust_name(); - - let trait_block = aster::AstBuilder::new() - .item() - .pub_() - .trait_(&trait_name) - .with_items(trait_items) - .build(); - - let ty_for_impl = quote_ty!(ctx.ext_cx(), id); - let impl_block = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id(&trait_name) - .build() - .with_items(impl_items) - .build_ty(ty_for_impl); - - result.push(trait_block); - result.push(impl_block); - result.saw_objc(); - } -} - - - -pub fn codegen(context: &mut BindgenContext) -> Vec> { - context.gen(|context| { - let counter = Cell::new(0); - let mut result = CodegenResult::new(&counter); - - debug!("codegen: {:?}", context.options()); - - let whitelisted_items: ItemSet = context.whitelisted_items().collect(); - - if context.options().emit_ir { - for &id in whitelisted_items.iter() { - let item = context.resolve_item(id); - println!("ir: {:?} = {:#?}", id, item); - } - } - - if let Some(path) = context.options().emit_ir_graphviz.as_ref() { - match dot::write_dot_file(context, path) { - Ok(()) => info!("Your dot file was generated successfully into: {}", path), - Err(e) => error!("{}", e), - } - } - - context.resolve_item(context.root_module()) - .codegen(context, &mut result, &whitelisted_items, &()); - - result.items - }) -} - -mod utils { - use super::{error, TryToRustTy, ToRustTyOrOpaque}; - use aster; - use ir::context::{BindgenContext, ItemId}; - use ir::function::FunctionSig; - use ir::item::{Item, ItemCanonicalPath}; - use ir::ty::TypeKind; - use std::mem; - use syntax::ast; - use syntax::ptr::P; - - pub fn prepend_objc_header(ctx: &BindgenContext, - result: &mut Vec>) { - let use_objc = if ctx.options().objc_extern_crate { - quote_item!(ctx.ext_cx(), - use objc; - ) - .unwrap() - } else { - quote_item!(ctx.ext_cx(), - #[macro_use] - extern crate objc; - ) - .unwrap() - }; - - - let id_type = quote_item!(ctx.ext_cx(), - #[allow(non_camel_case_types)] - pub type id = *mut objc::runtime::Object; - ) - .unwrap(); - - let items = vec![use_objc, id_type]; - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_union_types(ctx: &BindgenContext, - result: &mut Vec>) { - let prefix = ctx.trait_prefix(); - - // TODO(emilio): The fmt::Debug impl could be way nicer with - // std::intrinsics::type_name, but... - let union_field_decl = quote_item!(ctx.ext_cx(), - #[repr(C)] - pub struct __BindgenUnionField( - ::$prefix::marker::PhantomData); - ) - .unwrap(); - - let union_field_impl = quote_item!(&ctx.ext_cx(), - impl __BindgenUnionField { - #[inline] - pub fn new() -> Self { - __BindgenUnionField(::$prefix::marker::PhantomData) - } - - #[inline] - pub unsafe fn as_ref(&self) -> &T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { - ::$prefix::mem::transmute(self) - } - } - ) - .unwrap(); - - let union_field_default_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::default::Default for __BindgenUnionField { - #[inline] - fn default() -> Self { - Self::new() - } - } - ) - .unwrap(); - - let union_field_clone_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::clone::Clone for __BindgenUnionField { - #[inline] - fn clone(&self) -> Self { - Self::new() - } - } - ) - .unwrap(); - - let union_field_copy_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::marker::Copy for __BindgenUnionField {} - ) - .unwrap(); - - let union_field_debug_impl = quote_item!(ctx.ext_cx(), - impl ::$prefix::fmt::Debug for __BindgenUnionField { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { - fmt.write_str("__BindgenUnionField") - } - } - ) - .unwrap(); - - let items = vec![union_field_decl, - union_field_impl, - union_field_default_impl, - union_field_clone_impl, - union_field_copy_impl, - union_field_debug_impl]; - - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_incomplete_array_types(ctx: &BindgenContext, - result: &mut Vec>) { - let prefix = ctx.trait_prefix(); - - let incomplete_array_decl = quote_item!(ctx.ext_cx(), - #[repr(C)] - #[derive(Default)] - pub struct __IncompleteArrayField( - ::$prefix::marker::PhantomData); - ) - .unwrap(); - - let incomplete_array_impl = quote_item!(&ctx.ext_cx(), - impl __IncompleteArrayField { - #[inline] - pub fn new() -> Self { - __IncompleteArrayField(::$prefix::marker::PhantomData) - } - - #[inline] - pub unsafe fn as_ptr(&self) -> *const T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_mut_ptr(&mut self) -> *mut T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_slice(&self, len: usize) -> &[T] { - ::$prefix::slice::from_raw_parts(self.as_ptr(), len) - } - - #[inline] - pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { - ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) - } - } - ) - .unwrap(); - - let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), - impl ::$prefix::fmt::Debug for __IncompleteArrayField { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { - fmt.write_str("__IncompleteArrayField") - } - } - ) - .unwrap(); - - let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::clone::Clone for __IncompleteArrayField { - #[inline] - fn clone(&self) -> Self { - Self::new() - } - } - ) - .unwrap(); - - let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::marker::Copy for __IncompleteArrayField {} - ) - .unwrap(); - - let items = vec![incomplete_array_decl, - incomplete_array_impl, - incomplete_array_debug_impl, - incomplete_array_clone_impl, - incomplete_array_copy_impl]; - - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_complex_type(ctx: &BindgenContext, - result: &mut Vec>) { - let complex_type = quote_item!(ctx.ext_cx(), - #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] - #[repr(C)] - pub struct __BindgenComplex { - pub re: T, - pub im: T - } - ) - .unwrap(); - - let items = vec![complex_type]; - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn build_templated_path(item: &Item, - ctx: &BindgenContext, - template_params: Vec) - -> error::Result> { - let path = item.namespace_aware_canonical_path(ctx); - let builder = aster::AstBuilder::new().ty().path(); - - let template_params = template_params.iter() - .map(|param| param.try_to_rust_ty(ctx, &())) - .collect::>>()?; - - // XXX: I suck at aster. - if path.len() == 1 { - return Ok(builder.segment(&path[0]) - .with_tys(template_params) - .build() - .build()); - } - - let mut builder = builder.id(&path[0]); - for (i, segment) in path.iter().skip(1).enumerate() { - // Take into account the skip(1) - builder = if i == path.len() - 2 { - // XXX Extra clone courtesy of the borrow checker. - builder.segment(&segment) - .with_tys(template_params.clone()) - .build() - } else { - builder.segment(&segment).build() - } - } - - Ok(builder.build()) - } - - fn primitive_ty(ctx: &BindgenContext, name: &str) -> P { - let ident = ctx.rust_ident_raw(&name); - quote_ty!(ctx.ext_cx(), $ident) - } - - pub fn type_from_named(ctx: &BindgenContext, - name: &str, - _inner: ItemId) - -> Option> { - // FIXME: We could use the inner item to check this is really a - // primitive type but, who the heck overrides these anyway? - Some(match name { - "int8_t" => primitive_ty(ctx, "i8"), - "uint8_t" => primitive_ty(ctx, "u8"), - "int16_t" => primitive_ty(ctx, "i16"), - "uint16_t" => primitive_ty(ctx, "u16"), - "int32_t" => primitive_ty(ctx, "i32"), - "uint32_t" => primitive_ty(ctx, "u32"), - "int64_t" => primitive_ty(ctx, "i64"), - "uint64_t" => primitive_ty(ctx, "u64"), - - "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), - - "intptr_t" | "ptrdiff_t" | "ssize_t" => { - primitive_ty(ctx, "isize") - } - _ => return None, - }) - } - - pub fn rust_fndecl_from_signature(ctx: &BindgenContext, - sig: &Item) - -> P { - let signature = sig.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How?"), - }; - - let decl_ty = signature.try_to_rust_ty(ctx, &()) - .expect("function signature to Rust type conversion is infallible"); - match decl_ty.unwrap().node { - ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, - _ => panic!("How did this happen exactly?"), - } - } - - pub fn fnsig_return_ty(ctx: &BindgenContext, - sig: &FunctionSig) - -> ast::FunctionRetTy { - let return_item = ctx.resolve_item(sig.return_type()); - if let TypeKind::Void = *return_item.kind().expect_type().kind() { - ast::FunctionRetTy::Default(ctx.span()) - } else { - ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) - } - } - - pub fn fnsig_arguments(ctx: &BindgenContext, - sig: &FunctionSig) - -> Vec { - use super::ToPtr; - let mut unnamed_arguments = 0; - sig.argument_types().iter().map(|&(ref name, ty)| { - let arg_item = ctx.resolve_item(ty); - let arg_ty = arg_item.kind().expect_type(); - - // From the C90 standard[1]: - // - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - // - // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html - let arg_ty = match *arg_ty.canonical_type(ctx).kind() { - TypeKind::Array(t, _) => { - t.to_rust_ty_or_opaque(ctx, &()) - .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) - }, - TypeKind::Pointer(inner) => { - let inner = ctx.resolve_item(inner); - let inner_ty = inner.expect_type(); - if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { - quote_ty!(ctx.ext_cx(), id) - } else { - arg_item.to_rust_ty_or_opaque(ctx, &()) - } - }, - _ => { - arg_item.to_rust_ty_or_opaque(ctx, &()) - } - }; - - let arg_name = match *name { - Some(ref name) => ctx.rust_mangle(name).into_owned(), - None => { - unnamed_arguments += 1; - format!("arg{}", unnamed_arguments) - } - }; - - assert!(!arg_name.is_empty()); - - ast::Arg { - ty: arg_ty, - pat: aster::AstBuilder::new().pat().id(arg_name), - id: ast::DUMMY_NODE_ID, - } - }).collect::>() - } -} +mod error; +mod helpers; +mod struct_layout; + +use self::helpers::{BlobTyBuilder, attributes}; +use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; +use self::struct_layout::{align_to, bytes_from_bits}; +use aster; + +use ir::annotations::FieldAccessorKind; +use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; +use ir::context::{BindgenContext, ItemId}; +use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use ir::dot; +use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; +use ir::function::{Function, FunctionSig}; +use ir::int::IntKind; +use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath, + ItemSet}; +use ir::item_kind::ItemKind; +use ir::layout::Layout; +use ir::module::Module; +use ir::objc::{ObjCInterface, ObjCMethod}; +use ir::template::{AsNamed, TemplateInstantiation}; +use ir::ty::{TemplateDeclaration, Type, TypeKind}; +use ir::var::Var; + +use std::borrow::Cow; +use std::cell::Cell; +use std::cmp; +use std::collections::{HashSet, VecDeque}; +use std::collections::hash_map::{Entry, HashMap}; +use std::fmt::Write; +use std::mem; +use std::ops; +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{Span, respan}; +use syntax::ptr::P; + +fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { + if !ctx.options().enable_cxx_namespaces { + return 0; + } + + item.ancestors(ctx) + .filter(|id| ctx.resolve_item(*id).is_module()) + .fold(1, |i, _| i + 1) +} + +fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec { + let mut path = vec![ctx.rust_ident_raw("self")]; + + if ctx.options().enable_cxx_namespaces { + let super_ = ctx.rust_ident_raw("super"); + + for _ in 0..root_import_depth(ctx, item) { + path.push(super_.clone()); + } + } + + path +} + +fn root_import(ctx: &BindgenContext, module: &Item) -> P { + assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); + assert!(module.is_module()); + + let mut path = top_level_path(ctx, module); + + let root = ctx.root_module().canonical_name(ctx); + let root_ident = ctx.rust_ident(&root); + path.push(root_ident); + + let use_root = aster::AstBuilder::new() + .item() + .use_() + .ids(path) + .build() + .build(); + + quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() +} + +struct CodegenResult<'a> { + items: Vec>, + + /// A monotonic counter used to add stable unique id's to stuff that doesn't + /// need to be referenced by anything. + codegen_id: &'a Cell, + + /// Whether an union has been generated at least once. + saw_union: bool, + + /// Whether an incomplete array has been generated at least once. + saw_incomplete_array: bool, + + /// Whether Objective C types have been seen at least once. + saw_objc: bool, + + items_seen: HashSet, + /// The set of generated function/var names, needed because in C/C++ is + /// legal to do something like: + /// + /// ```c++ + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// ``` + /// + /// Being these two different declarations. + functions_seen: HashSet, + vars_seen: HashSet, + + /// Used for making bindings to overloaded functions. Maps from a canonical + /// function name to the number of overloads we have already codegen'd for + /// that name. This lets us give each overload a unique suffix. + overload_counters: HashMap, +} + +impl<'a> CodegenResult<'a> { + fn new(codegen_id: &'a Cell) -> Self { + CodegenResult { + items: vec![], + saw_union: false, + saw_incomplete_array: false, + saw_objc: false, + codegen_id: codegen_id, + items_seen: Default::default(), + functions_seen: Default::default(), + vars_seen: Default::default(), + overload_counters: Default::default(), + } + } + + fn saw_union(&mut self) { + self.saw_union = true; + } + + fn saw_incomplete_array(&mut self) { + self.saw_incomplete_array = true; + } + + fn saw_objc(&mut self) { + self.saw_objc = true; + } + + fn seen(&self, item: ItemId) -> bool { + self.items_seen.contains(&item) + } + + fn set_seen(&mut self, item: ItemId) { + self.items_seen.insert(item); + } + + fn seen_function(&self, name: &str) -> bool { + self.functions_seen.contains(name) + } + + fn saw_function(&mut self, name: &str) { + self.functions_seen.insert(name.into()); + } + + /// Get the overload number for the given function name. Increments the + /// counter internally so the next time we ask for the overload for this + /// name, we get the incremented value, and so on. + fn overload_number(&mut self, name: &str) -> u32 { + let mut counter = + self.overload_counters.entry(name.into()).or_insert(0); + let number = *counter; + *counter += 1; + number + } + + fn seen_var(&self, name: &str) -> bool { + self.vars_seen.contains(name) + } + + fn saw_var(&mut self, name: &str) { + self.vars_seen.insert(name.into()); + } + + fn inner(&mut self, cb: F) -> Vec> + where F: FnOnce(&mut Self), + { + let mut new = Self::new(self.codegen_id); + + cb(&mut new); + + self.saw_union |= new.saw_union; + self.saw_incomplete_array |= new.saw_incomplete_array; + self.saw_objc |= new.saw_objc; + + new.items + } +} + +impl<'a> ops::Deref for CodegenResult<'a> { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl<'a> ops::DerefMut for CodegenResult<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +struct ForeignModBuilder { + inner: ast::ForeignMod, +} + +impl ForeignModBuilder { + fn new(abi: Abi) -> Self { + ForeignModBuilder { + inner: ast::ForeignMod { + abi: abi, + items: vec![], + }, + } + } + + fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { + self.inner.items.push(item); + self + } + + #[allow(dead_code)] + fn with_foreign_items(mut self, items: I) -> Self + where I: IntoIterator, + { + self.inner.items.extend(items.into_iter()); + self + } + + fn build(self, ctx: &BindgenContext) -> P { + use syntax::codemap::DUMMY_SP; + P(ast::Item { + ident: ctx.rust_ident(""), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::ForeignMod(self.inner), + vis: ast::Visibility::Public, + attrs: vec![], + span: DUMMY_SP, + }) + } +} + +/// A trait to convert a rust type into a pointer, optionally const, to the same +/// type. +/// +/// This is done due to aster's lack of pointer builder, I guess I should PR +/// there. +trait ToPtr { + fn to_ptr(self, is_const: bool, span: Span) -> P; +} + +impl ToPtr for P { + fn to_ptr(self, is_const: bool, span: Span) -> Self { + let ty = ast::TyKind::Ptr(ast::MutTy { + ty: self, + mutbl: if is_const { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }, + }); + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ty, + span: span, + }) + } +} + +trait CodeGenerator { + /// Extra information from the caller. + type Extra; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + extra: &Self::Extra); +} + +impl CodeGenerator for Item { + type Extra = (); + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _extra: &()) { + if self.is_hidden(ctx) || result.seen(self.id()) { + debug!("::codegen: Ignoring hidden or seen: \ + self = {:?}", + self); + return; + } + + debug!("::codegen: self = {:?}", self); + if !whitelisted_items.contains(&self.id()) { + // TODO(emilio, #453): Figure out what to do when this happens + // legitimately, we could track the opaque stuff and disable the + // assertion there I guess. + error!("Found non-whitelisted item in code generation: {:?}", self); + } + + result.set_seen(self.id()); + + match *self.kind() { + ItemKind::Module(ref module) => { + module.codegen(ctx, result, whitelisted_items, self); + } + ItemKind::Function(ref fun) => { + if ctx.options().codegen_config.functions { + fun.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Var(ref var) => { + if ctx.options().codegen_config.vars { + var.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Type(ref ty) => { + if ctx.options().codegen_config.types { + ty.codegen(ctx, result, whitelisted_items, self); + } + } + } + } +} + +impl CodeGenerator for Module { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let codegen_self = |result: &mut CodegenResult, + found_any: &mut bool| { + for child in self.children() { + if whitelisted_items.contains(child) { + *found_any = true; + ctx.resolve_item(*child) + .codegen(ctx, result, whitelisted_items, &()); + } + } + + if item.id() == ctx.root_module() { + if result.saw_union && !ctx.options().unstable_rust { + utils::prepend_union_types(ctx, &mut *result); + } + if result.saw_incomplete_array { + utils::prepend_incomplete_array_types(ctx, &mut *result); + } + if ctx.need_bindegen_complex_type() { + utils::prepend_complex_type(ctx, &mut *result); + } + if result.saw_objc { + utils::prepend_objc_header(ctx, &mut *result); + } + } + }; + + if !ctx.options().enable_cxx_namespaces || + (self.is_inline() && !ctx.options().conservative_inline_namespaces) { + codegen_self(result, &mut false); + return; + } + + let mut found_any = false; + let inner_items = result.inner(|result| { + result.push(root_import(ctx, item)); + codegen_self(result, &mut found_any); + }); + + // Don't bother creating an empty module. + if !found_any { + return; + } + + let module = ast::ItemKind::Mod(ast::Mod { + inner: ctx.span(), + items: inner_items, + }); + + let name = item.canonical_name(ctx); + let item_builder = aster::AstBuilder::new() + .item() + .pub_(); + let item = if name == "root" { + let attrs = &["non_snake_case", + "non_camel_case_types", + "non_upper_case_globals"]; + item_builder.with_attr(attributes::allow(attrs)) + .build_item_kind(name, module) + } else { + item_builder.build_item_kind(name, module) + }; + + result.push(item); + } +} + +impl CodeGenerator for Var { + type Extra = Item; + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + use ir::var::VarType; + debug!("::codegen: item = {:?}", item); + + let canonical_name = item.canonical_name(ctx); + + if result.seen_var(&canonical_name) { + return; + } + result.saw_var(&canonical_name); + + let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + + if let Some(val) = self.val() { + let const_item = aster::AstBuilder::new() + .item() + .pub_() + .const_(canonical_name) + .expr(); + let item = match *val { + VarType::Bool(val) => { + const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) + } + VarType::Int(val) => { + const_item.build(helpers::ast_ty::int_expr(val)).build(ty) + } + VarType::String(ref bytes) => { + // Account the trailing zero. + // + // TODO: Here we ignore the type we just made up, probably + // we should refactor how the variable type and ty id work. + let len = bytes.len() + 1; + let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); + + match String::from_utf8(bytes.clone()) { + Ok(string) => { + const_item.build(helpers::ast_ty::cstr_expr(string)) + .build(quote_ty!(ctx.ext_cx(), &'static $ty)) + } + Err(..) => { + const_item + .build(helpers::ast_ty::byte_array_expr(bytes)) + .build(ty) + } + } + } + VarType::Float(f) => { + match helpers::ast_ty::float_expr(ctx, f) { + Ok(expr) => { + const_item.build(expr).build(ty) + } + Err(..) => return, + } + } + VarType::Char(c) => { + const_item + .build(aster::AstBuilder::new().expr().lit().byte(c)) + .build(ty) + } + }; + + result.push(item); + } else { + let mut attrs = vec![]; + if let Some(mangled) = self.mangled_name() { + attrs.push(attributes::link_name(mangled)); + } else if canonical_name != self.name() { + attrs.push(attributes::link_name(self.name())); + } + + let item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attrs, + node: ast::ForeignItemKind::Static(ty, !self.is_const()), + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(Abi::C) + .with_foreign_item(item) + .build(ctx); + result.push(item); + } + } +} + +impl CodeGenerator for Type { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + match *self.kind() { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Array(..) | + TypeKind::Pointer(..) | + TypeKind::BlockPointer | + TypeKind::Reference(..) | + TypeKind::Function(..) | + TypeKind::ResolvedTypeRef(..) | + TypeKind::Opaque | + TypeKind::Named => { + // These items don't need code generation, they only need to be + // converted to rust types in fields, arguments, and such. + return; + } + TypeKind::TemplateInstantiation(ref inst) => { + inst.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::Comp(ref ci) => { + ci.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::TemplateAlias(inner, _) | + TypeKind::Alias(inner) => { + let inner_item = ctx.resolve_item(inner); + let name = item.canonical_name(ctx); + + // Try to catch the common pattern: + // + // typedef struct foo { ... } foo; + // + // here. + // + if inner_item.canonical_name(ctx) == name { + return; + } + + // If this is a known named type, disallow generating anything + // for it too. + let spelling = self.name().expect("Unnamed alias?"); + if utils::type_from_named(ctx, spelling, inner).is_some() { + return; + } + + let mut used_template_params = item.used_template_params(ctx); + let inner_rust_type = if item.is_opaque(ctx) { + used_template_params = None; + self.to_opaque(ctx, item) + } else { + // Its possible that we have better layout information than + // the inner type does, so fall back to an opaque blob based + // on our layout if converting the inner item fails. + inner_item.try_to_rust_ty_or_opaque(ctx, &()) + .unwrap_or_else(|_| self.to_opaque(ctx, item)) + }; + + { + // FIXME(emilio): This is a workaround to avoid generating + // incorrect type aliases because of types that we haven't + // been able to resolve (because, eg, they depend on a + // template parameter). + // + // It's kind of a shame not generating them even when they + // could be referenced, but we already do the same for items + // with invalid template parameters, and at least this way + // they can be replaced, instead of generating plain invalid + // code. + let inner_canon_type = inner_item.expect_type() + .canonical_type(ctx); + if inner_canon_type.is_invalid_named_type() { + warn!("Item contained invalid named type, skipping: \ + {:?}, {:?}", + item, + inner_item); + return; + } + } + + let rust_name = ctx.rust_ident(&name); + let mut typedef = aster::AstBuilder::new().item().pub_(); + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + typedef = typedef.attr().doc(comment); + } + } + + // We prefer using `pub use` over `pub type` because of: + // https://github.com/rust-lang/rust/issues/26264 + let simple_enum_path = match inner_rust_type.node { + ast::TyKind::Path(None, ref p) => { + if used_template_params.is_none() && + inner_item.expect_type() + .canonical_type(ctx) + .is_enum() && + p.segments.iter().all(|p| p.parameters.is_none()) { + Some(p.clone()) + } else { + None + } + } + _ => None, + }; + + let typedef = if let Some(mut p) = simple_enum_path { + for ident in top_level_path(ctx, item).into_iter().rev() { + p.segments.insert(0, + ast::PathSegment { + identifier: ident, + parameters: None, + }); + } + typedef.use_().build(p).as_(rust_name) + } else { + let mut generics = typedef.type_(rust_name).generics(); + if let Some(ref params) = used_template_params { + for template_param in params { + if let Some(id) = + template_param.as_named(ctx, &()) { + let template_param = ctx.resolve_type(id); + if template_param.is_invalid_named_type() { + warn!("Item contained invalid template \ + parameter: {:?}", + item); + return; + } + generics = + generics.ty_param_id(template_param.name() + .unwrap()); + } + } + } + generics.build().build_ty(inner_rust_type) + }; + result.push(typedef) + } + TypeKind::Enum(ref ei) => { + ei.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::ObjCId | TypeKind::ObjCSel => { + result.saw_objc(); + } + TypeKind::ObjCInterface(ref interface) => { + interface.codegen(ctx, result, whitelisted_items, item) + } + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +struct Vtable<'a> { + item_id: ItemId, + #[allow(dead_code)] + methods: &'a [Method], + #[allow(dead_code)] + base_classes: &'a [Base], +} + +impl<'a> Vtable<'a> { + fn new(item_id: ItemId, + methods: &'a [Method], + base_classes: &'a [Base]) + -> Self { + Vtable { + item_id: item_id, + methods: methods, + base_classes: base_classes, + } + } +} + +impl<'a> CodeGenerator for Vtable<'a> { + type Extra = Item; + + fn codegen<'b>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'b>, + _whitelisted_items: &ItemSet, + item: &Item) { + assert_eq!(item.id(), self.item_id); + // For now, generate an empty struct, later we should generate function + // pointers and whatnot. + let attributes = vec![attributes::repr("C")]; + + let vtable = aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .tuple_struct(self.canonical_name(ctx)) + .field() + .build_ty(helpers::ast_ty::raw_type(ctx, "c_void")) + .build(); + result.push(vtable); + } +} + +impl<'a> ItemCanonicalName for Vtable<'a> { + fn canonical_name(&self, ctx: &BindgenContext) -> String { + format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) + } +} + +impl<'a> TryToRustTy for Vtable<'a> { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) -> error::Result> { + Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) + } +} + +struct Bitfield<'a> { + index: &'a mut usize, + fields: Vec<&'a Field>, +} + +impl<'a> Bitfield<'a> { + fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self { + Bitfield { + index: index, + fields: fields, + } + } + + fn codegen_fields(self, + ctx: &BindgenContext, + parent: &CompInfo, + fields: &mut Vec, + methods: &mut Vec) + -> Layout { + // NOTE: What follows is reverse-engineered from LLVM's + // lib/AST/RecordLayoutBuilder.cpp + // + // FIXME(emilio): There are some differences between Microsoft and the + // Itanium ABI, but we'll ignore those and stick to Itanium for now. + // + // Also, we need to handle packed bitfields and stuff. + // TODO(emilio): Take into account C++'s wide bitfields, and + // packing, sigh. + let mut total_size_in_bits = 0; + let mut max_align = 0; + let mut unfilled_bits_in_last_unit = 0; + let mut field_size_in_bits = 0; + *self.index += 1; + let mut last_field_name = format!("_bitfield_{}", self.index); + let mut last_field_align = 0; + + // (name, mask, width, bitfield's type, bitfield's layout) + let mut bitfields: Vec<(&str, usize, usize, ast::Ty, Layout)> = vec![]; + + for field in self.fields { + let width = field.bitfield().unwrap() as usize; + let field_item = ctx.resolve_item(field.ty()); + let field_ty_layout = field_item.kind() + .expect_type() + .layout(ctx) + .expect("Bitfield without layout? Gah!"); + let field_align = field_ty_layout.align; + + if field_size_in_bits != 0 && + (width == 0 || width > unfilled_bits_in_last_unit) { + // We've finished a physical field, so flush it and its bitfields. + field_size_in_bits = align_to(field_size_in_bits, field_align); + fields.push(flush_bitfields(ctx, + parent, + field_size_in_bits, + last_field_align, + &last_field_name, + bitfields.drain(..), + methods)); + + // TODO(emilio): dedup this. + *self.index += 1; + last_field_name = format!("_bitfield_{}", self.index); + + // Now reset the size and the rest of stuff. + // unfilled_bits_in_last_unit = 0; + field_size_in_bits = 0; + last_field_align = 0; + } + + if let Some(name) = field.name() { + let field_item_ty = field_item.to_rust_ty_or_opaque(ctx, &()); + bitfields.push((name, + field_size_in_bits, + width, + field_item_ty.unwrap(), + field_ty_layout)); + } + + field_size_in_bits += width; + total_size_in_bits += width; + + let data_size = align_to(field_size_in_bits, field_align * 8); + + max_align = cmp::max(max_align, field_align); + + // NB: The width here is completely, absolutely intentional. + last_field_align = cmp::max(last_field_align, width); + + unfilled_bits_in_last_unit = data_size - field_size_in_bits; + } + + if field_size_in_bits != 0 { + // Flush the last physical field and its bitfields. + fields.push(flush_bitfields(ctx, + parent, + field_size_in_bits, + last_field_align, + &last_field_name, + bitfields.drain(..), + methods)); + } + + Layout::new(bytes_from_bits(total_size_in_bits), max_align) + } +} + +fn parent_has_method(ctx: &BindgenContext, + parent: &CompInfo, + name: &str) + -> bool { + parent.methods().iter().any(|method| { + let method_name = match *ctx.resolve_item(method.signature()).kind() { + ItemKind::Function(ref func) => func.name(), + ref otherwise => panic!("a method's signature should always be a \ + item of kind ItemKind::Function, found: \ + {:?}", + otherwise), + }; + + method_name == name || ctx.rust_mangle(&method_name) == name + }) +} + +fn bitfield_getter_name(ctx: &BindgenContext, + parent: &CompInfo, + bitfield_name: &str) + -> ast::Ident { + let name = ctx.rust_mangle(bitfield_name); + + if parent_has_method(ctx, parent, &name) { + let mut name = name.to_string(); + name.push_str("_bindgen_bitfield"); + return ctx.ext_cx().ident_of(&name); + } + + ctx.ext_cx().ident_of(&name) +} + +fn bitfield_setter_name(ctx: &BindgenContext, + parent: &CompInfo, + bitfield_name: &str) + -> ast::Ident { + let setter = format!("set_{}", bitfield_name); + let mut setter = ctx.rust_mangle(&setter).to_string(); + + if parent_has_method(ctx, parent, &setter) { + setter.push_str("_bindgen_bitfield"); + } + + ctx.ext_cx().ident_of(&setter) +} + +/// A physical field (which is a word or byte or ...) has many logical bitfields +/// contained within it, but not all bitfields are in the same physical field of +/// a struct. This function creates a single physical field and flushes all the +/// accessors for the logical `bitfields` within that physical field to the +/// outgoing `methods`. +fn flush_bitfields<'a, I>(ctx: &BindgenContext, + parent: &CompInfo, + field_size_in_bits: usize, + field_align: usize, + field_name: &str, + bitfields: I, + methods: &mut Vec) -> ast::StructField + where I: IntoIterator +{ + use aster::struct_field::StructFieldBuilder; + + let field_layout = Layout::new(bytes_from_bits_pow2(field_size_in_bits), + bytes_from_bits_pow2(field_align)); + let field_ty = BlobTyBuilder::new(field_layout).build(); + + let field = StructFieldBuilder::named(field_name) + .pub_() + .build_ty(field_ty.clone()); + + let field_int_ty = match field_layout.size { + 8 => quote_ty!(ctx.ext_cx(), u64), + 4 => quote_ty!(ctx.ext_cx(), u32), + 2 => quote_ty!(ctx.ext_cx(), u16), + 1 => quote_ty!(ctx.ext_cx(), u8), + _ => return field + }; + + for (name, offset, width, bitfield_ty, bitfield_layout) in bitfields { + let prefix = ctx.trait_prefix(); + let getter_name = bitfield_getter_name(ctx, parent, name); + let setter_name = bitfield_setter_name(ctx, parent, name); + let field_ident = ctx.ext_cx().ident_of(field_name); + + let bitfield_int_ty = BlobTyBuilder::new(bitfield_layout).build(); + + let mask: usize = ((1usize << width) - 1usize) << offset; + + let impl_item = quote_item!( + ctx.ext_cx(), + impl XxxIgnored { + #[inline] + pub fn $getter_name(&self) -> $bitfield_ty { + let mask = $mask as $field_int_ty; + let field_val: $field_int_ty = unsafe { + ::$prefix::mem::transmute(self.$field_ident) + }; + let val = (field_val & mask) >> $offset; + unsafe { + ::$prefix::mem::transmute(val as $bitfield_int_ty) + } + } + + #[inline] + pub fn $setter_name(&mut self, val: $bitfield_ty) { + let mask = $mask as $field_int_ty; + let val = val as $bitfield_int_ty as $field_int_ty; + + let mut field_val: $field_int_ty = unsafe { + ::$prefix::mem::transmute(self.$field_ident) + }; + field_val &= !mask; + field_val |= (val << $offset) & mask; + + self.$field_ident = unsafe { + ::$prefix::mem::transmute(field_val) + }; + } + } + ).unwrap(); + + match impl_item.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, items) => { + methods.extend(items.into_iter()); + }, + _ => unreachable!(), + }; + } + + field +} + +impl CodeGenerator for TemplateInstantiation { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + // Although uses of instantiations don't need code generation, and are + // just converted to rust types in fields, vars, etc, we take this + // opportunity to generate tests for their layout here. + if !ctx.options().layout_tests { + return + } + + let layout = item.kind().expect_type().layout(ctx); + + if let Some(layout) = layout { + let size = layout.size; + let align = layout.align; + + let name = item.canonical_name(ctx); + let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", + name, + item.id().as_usize()); + let fn_name = ctx.rust_ident_raw(&fn_name); + + let prefix = ctx.trait_prefix(); + let ident = item.to_rust_ty_or_opaque(ctx, &()); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + + let item = quote_item!( + ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size, + concat!("Size of template specialization: ", stringify!($ident))); + assert_eq!($align_of_expr, $align, + concat!("Alignment of template specialization: ", stringify!($ident))); + }) + .unwrap(); + + result.push(item); + } + } +} + +impl CodeGenerator for CompInfo { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + use aster::struct_field::StructFieldBuilder; + + debug!("::codegen: item = {:?}", item); + + // Don't output classes with template parameters that aren't types, and + // also don't output template specializations, neither total or partial. + if self.has_non_type_template_params() { + return; + } + + let used_template_params = item.used_template_params(ctx); + + // generate tuple struct if struct or union is a forward declaration, + // skip for now if template parameters are needed. + if self.is_forward_declaration() && used_template_params.is_none() { + let struct_name = item.canonical_name(ctx); + let struct_name = ctx.rust_ident_raw(&struct_name); + let tuple_struct = quote_item!(ctx.ext_cx(), + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct $struct_name([u8; 0]); + ) + .unwrap(); + result.push(tuple_struct); + return; + } + + let mut attributes = vec![]; + let mut needs_clone_impl = false; + let mut needs_default_impl = false; + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + } + if self.packed() { + attributes.push(attributes::repr_list(&["C", "packed"])); + } else { + attributes.push(attributes::repr("C")); + } + + let is_union = self.kind() == CompKind::Union; + let mut derives = vec![]; + if item.can_derive_debug(ctx, ()) { + derives.push("Debug"); + } + + if item.can_derive_default(ctx, ()) { + derives.push("Default"); + } else { + needs_default_impl = ctx.options().derive_default; + } + + if item.can_derive_copy(ctx, ()) && + !item.annotations().disallow_copy() { + derives.push("Copy"); + if used_template_params.is_some() { + // FIXME: This requires extra logic if you have a big array in a + // templated struct. The reason for this is that the magic: + // fn clone(&self) -> Self { *self } + // doesn't work for templates. + // + // It's not hard to fix though. + derives.push("Clone"); + } else { + needs_clone_impl = true; + } + } + + if !derives.is_empty() { + attributes.push(attributes::derives(&derives)) + } + + let canonical_name = item.canonical_name(ctx); + let builder = if is_union && ctx.options().unstable_rust { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .union_(&canonical_name) + } else { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .struct_(&canonical_name) + }; + + // Generate the vtable from the method list if appropriate. + // + // TODO: I don't know how this could play with virtual methods that are + // not in the list of methods found by us, we'll see. Also, could the + // order of the vtable pointers vary? + // + // FIXME: Once we generate proper vtables, we need to codegen the + // vtable, but *not* generate a field for it in the case that + // needs_explicit_vtable is false but has_vtable is true. + // + // Also, we need to generate the vtable in such a way it "inherits" from + // the parent too. + let mut fields = vec![]; + let mut struct_layout = StructLayoutTracker::new(ctx, self); + if self.needs_explicit_vtable(ctx) { + let vtable = + Vtable::new(item.id(), self.methods(), self.base_members()); + vtable.codegen(ctx, result, whitelisted_items, item); + + let vtable_type = vtable.try_to_rust_ty(ctx, &()) + .expect("vtable to Rust type conversion is infallible") + .to_ptr(true, ctx.span()); + + let vtable_field = StructFieldBuilder::named("vtable_") + .pub_() + .build_ty(vtable_type); + + struct_layout.saw_vtable(); + + fields.push(vtable_field); + } + + for (i, base) in self.base_members().iter().enumerate() { + // Virtual bases are already taken into account by the vtable + // pointer. + // + // FIXME(emilio): Is this always right? + if base.is_virtual() { + continue; + } + + let base_ty = ctx.resolve_type(base.ty); + // NB: We won't include unsized types in our base chain because they + // would contribute to our size given the dummy field we insert for + // unsized types. + if base_ty.is_unsized(ctx) { + continue; + } + + let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); + let field_name = if i == 0 { + "_base".into() + } else { + format!("_base_{}", i) + }; + + struct_layout.saw_base(base_ty); + + let field = StructFieldBuilder::named(field_name) + .pub_() + .build_ty(inner); + fields.push(field); + } + if is_union { + result.saw_union(); + } + + let layout = item.kind().expect_type().layout(ctx); + + let mut current_bitfield_width = None; + let mut current_bitfield_layout: Option = None; + let mut current_bitfield_fields = vec![]; + let mut bitfield_count = 0; + let struct_fields = self.fields(); + let fields_should_be_private = item.annotations() + .private_fields() + .unwrap_or(false); + let struct_accessor_kind = item.annotations() + .accessor_kind() + .unwrap_or(FieldAccessorKind::None); + + let mut methods = vec![]; + let mut anonymous_field_count = 0; + for field in struct_fields { + debug_assert_eq!(current_bitfield_width.is_some(), + current_bitfield_layout.is_some()); + debug_assert_eq!(current_bitfield_width.is_some(), + !current_bitfield_fields.is_empty()); + + let field_ty = ctx.resolve_type(field.ty()); + + // Try to catch a bitfield contination early. + if let (Some(ref mut bitfield_width), Some(width)) = + (current_bitfield_width, field.bitfield()) { + let layout = current_bitfield_layout.unwrap(); + debug!("Testing bitfield continuation {} {} {:?}", + *bitfield_width, + width, + layout); + if *bitfield_width + width <= (layout.size * 8) as u32 { + *bitfield_width += width; + current_bitfield_fields.push(field); + continue; + } + } + + // Flush the current bitfield. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = + mem::replace(&mut current_bitfield_fields, vec![]); + let bitfield_layout = Bitfield::new(&mut bitfield_count, + bitfield_fields) + .codegen_fields(ctx, self, &mut fields, &mut methods); + struct_layout.saw_bitfield_batch(bitfield_layout); + + current_bitfield_width = None; + current_bitfield_layout = None; + } + debug_assert!(current_bitfield_fields.is_empty()); + + if let Some(width) = field.bitfield() { + let layout = field_ty.layout(ctx) + .expect("Bitfield type without layout?"); + current_bitfield_width = Some(width); + current_bitfield_layout = Some(layout); + current_bitfield_fields.push(field); + continue; + } + + let ty = field.ty().to_rust_ty_or_opaque(ctx, &()); + + // NB: In unstable rust we use proper `union` types. + let ty = if is_union && !ctx.options().unstable_rust { + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) + } + } else if let Some(item) = + field_ty.is_incomplete_array(ctx) { + result.saw_incomplete_array(); + + let inner = item.to_rust_ty_or_opaque(ctx, &()); + + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) + } else { + quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) + } + } else { + ty + }; + + let mut attrs = vec![]; + if ctx.options().generate_comments { + if let Some(comment) = field.comment() { + attrs.push(attributes::doc(comment)); + } + } + let field_name = match field.name() { + Some(name) => ctx.rust_mangle(name).into_owned(), + None => { + anonymous_field_count += 1; + format!("__bindgen_anon_{}", anonymous_field_count) + } + }; + + if !is_union { + if let Some(padding_field) = + struct_layout.pad_field(&field_name, field_ty, field.offset()) { + fields.push(padding_field); + } + } + + let is_private = field.annotations() + .private_fields() + .unwrap_or(fields_should_be_private); + + let accessor_kind = field.annotations() + .accessor_kind() + .unwrap_or(struct_accessor_kind); + + let mut field = StructFieldBuilder::named(&field_name); + + if !is_private { + field = field.pub_(); + } + + let field = field.with_attrs(attrs) + .build_ty(ty.clone()); + + fields.push(field); + + // TODO: Factor the following code out, please! + if accessor_kind == FieldAccessorKind::None { + continue; + } + + let getter_name = + ctx.rust_ident_raw(&format!("get_{}", field_name)); + let mutable_getter_name = + ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); + let field_name = ctx.rust_ident_raw(&field_name); + + let accessor_methods_impl = match accessor_kind { + FieldAccessorKind::None => unreachable!(), + FieldAccessorKind::Regular => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Unsafe => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub unsafe fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub unsafe fn $mutable_getter_name(&mut self) + -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Immutable => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + } + ) + } + }; + + match accessor_methods_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => { + methods.extend(items.clone()) + } + _ => unreachable!(), + } + } + + // Flush the last bitfield if any. + // + // FIXME: Reduce duplication with the loop above. + // FIXME: May need to pass current_bitfield_layout too. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = mem::replace(&mut current_bitfield_fields, + vec![]); + let bitfield_layout = Bitfield::new(&mut bitfield_count, + bitfield_fields) + .codegen_fields(ctx, self, &mut fields, &mut methods); + struct_layout.saw_bitfield_batch(bitfield_layout); + } + debug_assert!(current_bitfield_fields.is_empty()); + + if is_union && !ctx.options().unstable_rust { + let layout = layout.expect("Unable to get layout information?"); + let ty = BlobTyBuilder::new(layout).build(); + let field = StructFieldBuilder::named("bindgen_union_field") + .pub_() + .build_ty(ty); + + struct_layout.saw_union(layout); + + fields.push(field); + } + + // Yeah, sorry about that. + if item.is_opaque(ctx) { + fields.clear(); + methods.clear(); + + match layout { + Some(l) => { + let ty = BlobTyBuilder::new(l).build(); + let field = + StructFieldBuilder::named("_bindgen_opaque_blob") + .pub_() + .build_ty(ty); + fields.push(field); + } + None => { + warn!("Opaque type without layout! Expect dragons!"); + } + } + } else if !is_union && !self.is_unsized(ctx) { + if let Some(padding_field) = + layout.and_then(|layout| { + struct_layout.pad_struct(&canonical_name, layout) + }) { + fields.push(padding_field); + } + + if let Some(align_field) = + layout.and_then(|layout| struct_layout.align_struct(layout)) { + fields.push(align_field); + } + } + + // C++ requires every struct to be addressable, so what C++ compilers do + // is making the struct 1-byte sized. + // + // This is apparently not the case for C, see: + // https://github.com/servo/rust-bindgen/issues/551 + // + // Just get the layout, and assume C++ if not. + // + // NOTE: This check is conveniently here to avoid the dummy fields we + // may add for unused template parameters. + if self.is_unsized(ctx) { + let has_address = layout.map_or(true, |l| l.size != 0); + if has_address { + let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); + let field = StructFieldBuilder::named("_address") + .pub_() + .build_ty(ty); + fields.push(field); + } + } + + let mut generics = aster::AstBuilder::new().generics(); + + if let Some(ref params) = used_template_params { + for (idx, ty) in params.iter().enumerate() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); + let ident = ctx.rust_ident(name); + + generics = generics.ty_param_id(ident); + + let prefix = ctx.trait_prefix(); + let phantom_ty = quote_ty!( + ctx.ext_cx(), + ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); + let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) + .build_ty(phantom_ty); + fields.push(phantom_field); + } + } + + let generics = generics.build(); + + let rust_struct = builder.with_generics(generics.clone()) + .with_fields(fields) + .build(); + result.push(rust_struct); + + // Generate the inner types and all that stuff. + // + // TODO: In the future we might want to be smart, and use nested + // modules, and whatnot. + for ty in self.inner_types() { + let child_item = ctx.resolve_item(*ty); + // assert_eq!(child_item.parent_id(), item.id()); + child_item.codegen(ctx, result, whitelisted_items, &()); + } + + // NOTE: Some unexposed attributes (like alignment attributes) may + // affect layout, so we're bad and pray to the gods for avoid sending + // all the tests to shit when parsing things like max_align_t. + if self.found_unknown_attr() { + warn!("Type {} has an unkown attribute that may affect layout", + canonical_name); + } + + if used_template_params.is_none() { + for var in self.inner_vars() { + ctx.resolve_item(*var) + .codegen(ctx, result, whitelisted_items, &()); + } + + if ctx.options().layout_tests { + if let Some(layout) = layout { + let fn_name = format!("bindgen_test_layout_{}", canonical_name); + let fn_name = ctx.rust_ident_raw(&fn_name); + let type_name = ctx.rust_ident_raw(&canonical_name); + let prefix = ctx.trait_prefix(); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$type_name>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$type_name>()); + let size = layout.size; + let align = layout.align; + + let check_struct_align = if align > mem::size_of::<*mut ()>() { + // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready + None + } else { + quote_item!(ctx.ext_cx(), + assert_eq!($align_of_expr, + $align, + concat!("Alignment of ", stringify!($type_name))); + ) + }; + + // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready + let too_many_base_vtables = self.base_members() + .iter() + .filter(|base| { + ctx.resolve_type(base.ty).has_vtable(ctx) + }) + .count() > 1; + + let should_skip_field_offset_checks = item.is_opaque(ctx) || + too_many_base_vtables; + + let check_field_offset = if should_skip_field_offset_checks { + None + } else { + let asserts = self.fields() + .iter() + .filter(|field| field.bitfield().is_none()) + .flat_map(|field| { + field.name().and_then(|name| { + field.offset().and_then(|offset| { + let field_offset = offset / 8; + let field_name = ctx.rust_ident(name); + + quote_item!(ctx.ext_cx(), + assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, + $field_offset, + concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); + ) + }) + }) + }).collect::>>(); + + Some(asserts) + }; + + let item = quote_item!(ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, + $size, + concat!("Size of: ", stringify!($type_name))); + + $check_struct_align + $check_field_offset + }) + .unwrap(); + result.push(item); + } + } + + let mut method_names = Default::default(); + if ctx.options().codegen_config.methods { + for method in self.methods() { + assert!(method.kind() != MethodKind::Constructor); + method.codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + + if ctx.options().codegen_config.constructors { + for sig in self.constructors() { + Method::new(MethodKind::Constructor, + *sig, + /* const */ + false) + .codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + + if ctx.options().codegen_config.destructors { + if let Some((is_virtual, destructor)) = self.destructor() { + let kind = if is_virtual { + MethodKind::VirtualDestructor + } else { + MethodKind::Destructor + }; + + Method::new(kind, destructor, false) + .codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + } + + // NB: We can't use to_rust_ty here since for opaque types this tries to + // use the specialization knowledge to generate a blob field. + let ty_for_impl = aster::AstBuilder::new() + .ty() + .path() + .segment(&canonical_name) + .with_generics(generics.clone()) + .build() + .build(); + + if needs_clone_impl { + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn clone(&self) -> Self { *self } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let clone_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Clone") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(clone_impl); + } + + if needs_default_impl { + let prefix = ctx.trait_prefix(); + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let default_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Default") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(default_impl); + } + + if !methods.is_empty() { + let methods = aster::AstBuilder::new() + .item() + .impl_() + .with_generics(generics) + .with_items(methods) + .build_ty(ty_for_impl); + result.push(methods); + } + } +} + +trait MethodCodegen { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + parent: &CompInfo); +} + +impl MethodCodegen for Method { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _parent: &CompInfo) { + if self.is_virtual() { + return; // FIXME + } + + // First of all, output the actual function. + let function_item = ctx.resolve_item(self.signature()); + function_item.codegen(ctx, result, whitelisted_items, &()); + + let function = function_item.expect_function(); + let signature_item = ctx.resolve_item(function.signature()); + let mut name = match self.kind() { + MethodKind::Constructor => "new".into(), + MethodKind::Destructor => "destruct".into(), + _ => function.name().to_owned(), + }; + + let signature = match *signature_item.expect_type().kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How in the world?"), + }; + + // Do not generate variadic methods, since rust does not allow + // implementing them, and we don't do a good job at it anyway. + if signature.is_variadic() { + return; + } + + let count = { + let mut count = method_names.entry(name.clone()) + .or_insert(0); + *count += 1; + *count - 1 + }; + + if count != 0 { + name.push_str(&count.to_string()); + } + + let function_name = function_item.canonical_name(ctx); + let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) + .unwrap(); + if !self.is_static() && !self.is_constructor() { + let mutability = if self.is_const() { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }; + + assert!(!fndecl.inputs.is_empty()); + + // FIXME: use aster here. + fndecl.inputs[0] = ast::Arg { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Rptr(None, ast::MutTy { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::ImplicitSelf, + span: ctx.span() + }), + mutbl: mutability, + }), + span: ctx.span(), + }), + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Ident( + ast::BindingMode::ByValue(ast::Mutability::Immutable), + respan(ctx.span(), ctx.ext_cx().ident_of("self")), + None + ), + span: ctx.span(), + }), + id: ast::DUMMY_NODE_ID, + }; + } + + // If it's a constructor, we always return `Self`, and we inject the + // "this" parameter, so there's no need to ask the user for it. + // + // Note that constructors in Clang are represented as functions with + // return-type = void. + if self.is_constructor() { + fndecl.inputs.remove(0); + fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), + Self)); + } + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Unsafe, + abi: Abi::Rust, + decl: P(fndecl), + generics: ast::Generics::default(), + constness: respan(ctx.span(), ast::Constness::NotConst), + }; + + let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, + ctx); + + let mut stmts = vec![]; + + // If it's a constructor, we need to insert an extra parameter with a + // variable called `__bindgen_tmp` we're going to create. + if self.is_constructor() { + let prefix = ctx.trait_prefix(); + let tmp_variable_decl = + quote_stmt!(ctx.ext_cx(), + let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) + .unwrap(); + stmts.push(tmp_variable_decl); + exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); + } else if !self.is_static() { + assert!(!exprs.is_empty()); + exprs[0] = quote_expr!(ctx.ext_cx(), self); + }; + + let call = aster::expr::ExprBuilder::new() + .call() + .id(function_name) + .with_args(exprs) + .build(); + + stmts.push(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(call), + span: ctx.span(), + }); + + if self.is_constructor() { + stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); + } + + let block = ast::Block { + stmts: stmts, + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let mut attrs = vec![]; + attrs.push(attributes::inline()); + + let item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(&name), + vis: ast::Visibility::Public, + attrs: attrs, + node: ast::ImplItemKind::Method(sig, P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + methods.push(item); + } +} + +/// A helper type to construct enums, either bitfield ones or rust-style ones. +enum EnumBuilder<'a> { + Rust(aster::item::ItemEnumBuilder), + Bitfield { + canonical_name: &'a str, + aster: P, + }, + Consts { aster: P }, +} + +impl<'a> EnumBuilder<'a> { + /// Create a new enum given an item builder, a canonical name, a name for + /// the representation, and whether it should be represented as a rust enum. + fn new(aster: aster::item::ItemBuilder, + name: &'a str, + repr: P, + bitfield_like: bool, + constify: bool) + -> Self { + if bitfield_like { + EnumBuilder::Bitfield { + canonical_name: name, + aster: aster.tuple_struct(name) + .field() + .pub_() + .build_ty(repr) + .build(), + } + } else if constify { + EnumBuilder::Consts { + aster: aster.type_(name).build_ty(repr), + } + } else { + EnumBuilder::Rust(aster.enum_(name)) + } + } + + /// Add a variant to this enum. + fn with_variant<'b>(self, + ctx: &BindgenContext, + variant: &EnumVariant, + mangling_prefix: Option<&String>, + rust_ty: P, + result: &mut CodegenResult<'b>) + -> Self { + let variant_name = ctx.rust_mangle(variant.name()); + let expr = aster::AstBuilder::new().expr(); + let expr = match variant.val() { + EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), + EnumVariantValue::Unsigned(v) => expr.uint(v), + }; + + match self { + EnumBuilder::Rust(b) => { + EnumBuilder::Rust(b.with_variant_(ast::Variant_ { + name: ctx.rust_ident(&*variant_name), + attrs: vec![], + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), + disr_expr: Some(expr), + })) + } + EnumBuilder::Bitfield { canonical_name, .. } => { + let constant_name = match mangling_prefix { + Some(prefix) => { + Cow::Owned(format!("{}_{}", prefix, variant_name)) + } + None => variant_name, + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*constant_name) + .expr() + .call() + .id(canonical_name) + .arg() + .build(expr) + .build() + .build(rust_ty); + result.push(constant); + self + } + EnumBuilder::Consts { .. } => { + let constant_name = match mangling_prefix { + Some(prefix) => { + Cow::Owned(format!("{}_{}", prefix, variant_name)) + } + None => variant_name, + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*constant_name) + .expr() + .build(expr) + .build(rust_ty); + + result.push(constant); + self + } + } + } + + fn build<'b>(self, + ctx: &BindgenContext, + rust_ty: P, + result: &mut CodegenResult<'b>) + -> P { + match self { + EnumBuilder::Rust(b) => b.build(), + EnumBuilder::Bitfield { canonical_name, aster } => { + let rust_ty_name = ctx.rust_ident_raw(canonical_name); + let prefix = ctx.trait_prefix(); + + let impl_ = quote_item!(ctx.ext_cx(), + impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { + type Output = Self; + + #[inline] + fn bitor(self, other: Self) -> Self { + $rust_ty_name(self.0 | other.0) + } + } + ) + .unwrap(); + + result.push(impl_); + aster + } + EnumBuilder::Consts { aster, .. } => aster, + } + } +} + +impl CodeGenerator for Enum { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let name = item.canonical_name(ctx); + let enum_ty = item.expect_type(); + let layout = enum_ty.layout(ctx); + + let repr = self.repr().map(|repr| ctx.resolve_type(repr)); + let repr = match repr { + Some(repr) => { + match *repr.canonical_type(ctx).kind() { + TypeKind::Int(int_kind) => int_kind, + _ => panic!("Unexpected type as enum repr"), + } + } + None => { + warn!("Guessing type of enum! Forward declarations of enums \ + shouldn't be legal!"); + IntKind::Int + } + }; + + let signed = repr.is_signed(); + let size = layout.map(|l| l.size) + .or_else(|| repr.known_size()) + .unwrap_or(0); + + let repr_name = match (signed, size) { + (true, 1) => "i8", + (false, 1) => "u8", + (true, 2) => "i16", + (false, 2) => "u16", + (true, 4) => "i32", + (false, 4) => "u32", + (true, 8) => "i64", + (false, 8) => "u64", + _ => { + warn!("invalid enum decl: signed: {}, size: {}", signed, size); + "i32" + } + }; + + let mut builder = aster::AstBuilder::new().item().pub_(); + + // FIXME(emilio): These should probably use the path so it can + // disambiguate between namespaces, just like is_opaque etc. + let is_bitfield = { + ctx.options().bitfield_enums.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) + }; + + let is_constified_enum = { + ctx.options().constified_enums.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().constified_enums.matches(&v.name()))) + }; + + let is_rust_enum = !is_bitfield && !is_constified_enum; + + // FIXME: Rust forbids repr with empty enums. Remove this condition when + // this is allowed. + // + // TODO(emilio): Delegate this to the builders? + if is_rust_enum { + if !self.variants().is_empty() { + builder = builder.with_attr(attributes::repr(repr_name)); + } + } else if is_bitfield { + builder = builder.with_attr(attributes::repr("C")); + } + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + builder = builder.with_attr(attributes::doc(comment)); + } + } + + if !is_constified_enum { + let derives = attributes::derives(&["Debug", + "Copy", + "Clone", + "PartialEq", + "Eq", + "Hash"]); + + builder = builder.with_attr(derives); + } + + fn add_constant<'a>(enum_: &Type, + // Only to avoid recomputing every time. + enum_canonical_name: &str, + // May be the same as "variant" if it's because the + // enum is unnamed and we still haven't seen the + // value. + variant_name: &str, + referenced_name: &str, + enum_rust_ty: P, + result: &mut CodegenResult<'a>) { + let constant_name = if enum_.name().is_some() { + format!("{}_{}", enum_canonical_name, variant_name) + } else { + variant_name.into() + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(constant_name) + .expr() + .path() + .ids(&[&*enum_canonical_name, referenced_name]) + .build() + .build(enum_rust_ty); + result.push(constant); + } + + let repr = self.repr() + .and_then(|repr| repr.try_to_rust_ty_or_opaque(ctx, &()).ok()) + .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); + + let mut builder = EnumBuilder::new(builder, + &name, + repr, + is_bitfield, + is_constified_enum); + + // A map where we keep a value -> variant relation. + let mut seen_values = HashMap::<_, String>::new(); + let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); + let is_toplevel = item.is_toplevel(ctx); + + // Used to mangle the constants we generate in the unnamed-enum case. + let parent_canonical_name = if is_toplevel { + None + } else { + Some(item.parent_id().canonical_name(ctx)) + }; + + let constant_mangling_prefix = if ctx.options().prepend_enum_name { + if enum_ty.name().is_none() { + parent_canonical_name.as_ref().map(|n| &*n) + } else { + Some(&name) + } + } else { + None + }; + + // NB: We defer the creation of constified variants, in case we find + // another variant with the same value (which is the common thing to + // do). + let mut constified_variants = VecDeque::new(); + + let mut iter = self.variants().iter().peekable(); + while let Some(variant) = iter.next() + .or_else(|| constified_variants.pop_front()) { + if variant.hidden() { + continue; + } + + if variant.force_constification() && iter.peek().is_some() { + constified_variants.push_back(variant); + continue; + } + + match seen_values.entry(variant.val()) { + Entry::Occupied(ref entry) => { + if is_rust_enum { + let variant_name = ctx.rust_mangle(variant.name()); + let mangled_name = if is_toplevel || + enum_ty.name().is_some() { + variant_name + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned(format!("{}_{}", + parent_name, + variant_name)) + }; + + let existing_variant_name = entry.get(); + add_constant(enum_ty, + &name, + &*mangled_name, + existing_variant_name, + enum_rust_ty.clone(), + result); + } else { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + } + } + Entry::Vacant(entry) => { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + + let variant_name = ctx.rust_mangle(variant.name()); + + // If it's an unnamed enum, or constification is enforced, + // we also generate a constant so it can be properly + // accessed. + if (is_rust_enum && enum_ty.name().is_none()) || + variant.force_constification() { + let mangled_name = if is_toplevel { + variant_name.clone() + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned(format!("{}_{}", + parent_name, + variant_name)) + }; + + add_constant(enum_ty, + &name, + &mangled_name, + &variant_name, + enum_rust_ty.clone(), + result); + } + + entry.insert(variant_name.into_owned()); + } + } + } + + let enum_ = builder.build(ctx, enum_rust_ty, result); + result.push(enum_); + } +} + +/// Fallible conversion to an opaque blob. +/// +/// Implementors of this trait should provide the `try_get_layout` method to +/// fallibly get this thing's layout, which the provided `try_to_opaque` trait +/// method will use to convert the `Layout` into an opaque blob Rust type. +trait TryToOpaque { + type Extra; + + /// Get the layout for this thing, if one is available. + fn try_get_layout(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result; + + /// Do not override this provided trait method. + fn try_to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result> { + self.try_get_layout(ctx, extra) + .map(|layout| BlobTyBuilder::new(layout).build()) + } +} + +/// Infallible conversion of an IR thing to an opaque blob. +/// +/// The resulting layout is best effort, and is unfortunately not guaranteed to +/// be correct. When all else fails, we fall back to a single byte layout as a +/// last resort, because C++ does not permit zero-sized types. See the note in +/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits +/// and when each is appropriate. +/// +/// Don't implement this directly. Instead implement `TryToOpaque`, and then +/// leverage the blanket impl for this trait. +trait ToOpaque: TryToOpaque { + fn get_layout(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> Layout { + self.try_get_layout(ctx, extra) + .unwrap_or_else(|_| Layout::for_size(1)) + } + + fn to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> P { + let layout = self.get_layout(ctx, extra); + BlobTyBuilder::new(layout).build() + } +} + +impl ToOpaque for T + where T: TryToOpaque +{} + +/// Fallible conversion from an IR thing to an *equivalent* Rust type. +/// +/// If the C/C++ construct represented by the IR thing cannot (currently) be +/// represented in Rust (for example, instantiations of templates with +/// const-value generic parameters) then the impl should return an `Err`. It +/// should *not* attempt to return an opaque blob with the correct size and +/// alignment. That is the responsibility of the `TryToOpaque` trait. +trait TryToRustTy { + type Extra; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result>; +} + +/// Fallible conversion to a Rust type or an opaque blob with the correct size +/// and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { + type Extra; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &::Extra) + -> error::Result>; +} + +impl TryToRustTyOrOpaque for T + where T: TryToRustTy + TryToOpaque +{ + type Extra = E; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> error::Result> { + self.try_to_rust_ty(ctx, extra) + .or_else(|_| { + if let Ok(layout) = self.try_get_layout(ctx, extra) { + Ok(BlobTyBuilder::new(layout).build()) + } else { + Err(error::Error::NoLayoutForOpaqueBlob) + } + }) + } +} + +/// Infallible conversion to a Rust type, or an opaque blob with a best effort +/// of correct size and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +/// +/// ### Fallible vs. Infallible Conversions to Rust Types +/// +/// When should one use this infallible `ToRustTyOrOpaque` trait versus the +/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait +/// implementations that need to convert another thing into a Rust type or +/// opaque blob in a nested manner should also use fallible trait methods and +/// propagate failure up the stack. Only infallible functions and methods like +/// CodeGenerator implementations should use the infallible +/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely +/// we are to get a usable `Layout` even if we can't generate an equivalent Rust +/// type for a C++ construct. +trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { + type Extra; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &::Extra) + -> P; +} + +impl ToRustTyOrOpaque for T + where T: TryToRustTy + ToOpaque +{ + type Extra = E; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> P { + self.try_to_rust_ty(ctx, extra) + .unwrap_or_else(|_| self.to_opaque(ctx, extra)) + } +} + +impl TryToOpaque for ItemId { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result { + ctx.resolve_item(*self).try_get_layout(ctx, &()) + } +} + +impl TryToRustTy for ItemId { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) + } +} + +impl TryToOpaque for Item { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result { + self.kind().expect_type().try_get_layout(ctx, self) + } +} + +impl TryToRustTy for Item { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + self.kind().expect_type().try_to_rust_ty(ctx, self) + } +} + +impl TryToOpaque for Type { + type Extra = Item; + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &Item) + -> error::Result { + self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for Type { + type Extra = Item; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + item: &Item) + -> error::Result> { + use self::helpers::ast_ty::*; + + match *self.kind() { + TypeKind::Void => Ok(raw_type(ctx, "c_void")), + // TODO: we should do something smart with nullptr, or maybe *const + // c_void is enough? + TypeKind::NullPtr => { + Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) + } + TypeKind::Int(ik) => { + match ik { + IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), + IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), + IntKind::SChar => Ok(raw_type(ctx, "c_schar")), + IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), + IntKind::Short => Ok(raw_type(ctx, "c_short")), + IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), + IntKind::Int => Ok(raw_type(ctx, "c_int")), + IntKind::UInt => Ok(raw_type(ctx, "c_uint")), + IntKind::Long => Ok(raw_type(ctx, "c_long")), + IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), + IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), + IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), + + IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), + IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), + IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), + IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), + IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), + IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), + IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), + IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), + IntKind::Custom { name, .. } => { + let ident = ctx.rust_ident_raw(name); + Ok(quote_ty!(ctx.ext_cx(), $ident)) + } + // FIXME: This doesn't generate the proper alignment, but we + // can't do better right now. We should be able to use + // i128/u128 when they're available. + IntKind::U128 | IntKind::I128 => { + Ok(aster::ty::TyBuilder::new().array(2).u64()) + } + } + } + TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), + TypeKind::Complex(fk) => { + let float_path = float_kind_rust_type(ctx, fk); + + ctx.generated_bindegen_complex(); + Ok(if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) + }) + } + TypeKind::Function(ref fs) => { + // We can't rely on the sizeof(Option>) == + // sizeof(NonZero<_>) optimization with opaque blobs (because + // they aren't NonZero), so don't *ever* use an or_opaque + // variant here. + let ty = fs.try_to_rust_ty(ctx, &())?; + + let prefix = ctx.trait_prefix(); + Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) + } + TypeKind::Array(item, len) => { + let ty = item.try_to_rust_ty(ctx, &())?; + Ok(aster::ty::TyBuilder::new().array(len).build(ty)) + } + TypeKind::Enum(..) => { + let path = item.namespace_aware_canonical_path(ctx); + Ok(aster::AstBuilder::new() + .ty() + .path() + .ids(path) + .build()) + } + TypeKind::TemplateInstantiation(ref inst) => { + inst.try_to_rust_ty(ctx, self) + } + TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), + TypeKind::TemplateAlias(inner, _) | + TypeKind::Alias(inner) => { + let template_params = item.used_template_params(ctx) + .unwrap_or(vec![]) + .into_iter() + .filter(|param| param.is_named(ctx, &())) + .collect::>(); + + let spelling = self.name().expect("Unnamed alias?"); + if item.is_opaque(ctx) && !template_params.is_empty() { + self.try_to_opaque(ctx, item) + } else if let Some(ty) = utils::type_from_named(ctx, + spelling, + inner) { + Ok(ty) + } else { + utils::build_templated_path(item, ctx, template_params) + } + } + TypeKind::Comp(ref info) => { + let template_params = item.used_template_params(ctx); + if info.has_non_type_template_params() || + (item.is_opaque(ctx) && template_params.is_some()) { + return self.try_to_opaque(ctx, item); + } + + let template_params = template_params.unwrap_or(vec![]); + utils::build_templated_path(item, + ctx, + template_params) + } + TypeKind::Opaque => { + self.try_to_opaque(ctx, item) + } + TypeKind::BlockPointer => { + let void = raw_type(ctx, "c_void"); + Ok(void.to_ptr(/* is_const = */ + false, + ctx.span())) + } + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + + // Regardless if we can properly represent the inner type, we + // should always generate a proper pointer here, so use + // infallible conversion of the inner type. + let ty = inner.to_rust_ty_or_opaque(ctx, &()); + + // Avoid the first function pointer level, since it's already + // represented in Rust. + if inner_ty.canonical_type(ctx).is_function() { + Ok(ty) + } else { + let is_const = self.is_const() || + inner.expect_type().is_const(); + Ok(ty.to_ptr(is_const, ctx.span())) + } + } + TypeKind::Named => { + let name = item.canonical_name(ctx); + let ident = ctx.rust_ident(&name); + Ok(quote_ty!(ctx.ext_cx(), $ident)) + } + TypeKind::ObjCSel => Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)), + TypeKind::ObjCId | + TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +impl TryToOpaque for TemplateInstantiation { + type Extra = Type; + + fn try_get_layout(&self, + ctx: &BindgenContext, + self_ty: &Type) + -> error::Result { + self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for TemplateInstantiation { + type Extra = Type; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &Type) + -> error::Result> { + let decl = self.template_definition(); + let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); + + let decl_params = match decl.self_template_params(ctx) { + Some(params) => params, + None => { + // This can happen if we generated an opaque type for a partial + // template specialization, and we've hit an instantiation of + // that partial specialization. + extra_assert!(ctx.resolve_type_through_type_refs(decl) + .is_opaque()); + return Err(error::Error::InstantiationOfOpaqueType); + } + }; + + // TODO: If the decl type is a template class/struct + // declaration's member template declaration, it could rely on + // generic template parameters from its outer template + // class/struct. When we emit bindings for it, it could require + // *more* type arguments than we have here, and we will need to + // reconstruct them somehow. We don't have any means of doing + // that reconstruction at this time. + + if let ast::TyKind::Path(_, ref mut path) = ty.node { + let template_args = self.template_arguments() + .iter() + .zip(decl_params.iter()) + // Only pass type arguments for the type parameters that + // the decl uses. + .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) + .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) + .collect::>>()?; + + path.segments.last_mut().unwrap().parameters = if + template_args.is_empty() { + None + } else { + Some(P(ast::PathParameters::AngleBracketed( + ast::AngleBracketedParameterData { + lifetimes: vec![], + types: template_args, + bindings: vec![], + } + ))) + } + } + + Ok(P(ty)) + } +} + +impl TryToRustTy for FunctionSig { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + // TODO: we might want to consider ignoring the reference return value. + let ret = utils::fnsig_return_ty(ctx, &self); + let arguments = utils::fnsig_arguments(ctx, &self); + + let decl = P(ast::FnDecl { + inputs: arguments, + output: ret, + variadic: self.is_variadic(), + }); + + let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: self.abi().expect("Invalid abi for function!"), + lifetimes: vec![], + decl: decl, + })); + + Ok(P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: fnty, + span: ctx.span(), + })) + } +} + +impl CodeGenerator for Function { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let name = self.name(); + let mut canonical_name = item.canonical_name(ctx); + let mangled_name = self.mangled_name(); + + { + let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); + + // TODO: Maybe warn here if there's a type/argument mismatch, or + // something? + if result.seen_function(seen_symbol_name) { + return; + } + result.saw_function(seen_symbol_name); + } + + let signature_item = ctx.resolve_item(self.signature()); + let signature = signature_item.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("Signature kind is not a Function: {:?}", signature), + }; + + let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); + + let mut attributes = vec![]; + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + } + + if let Some(mangled) = mangled_name { + attributes.push(attributes::link_name(mangled)); + } else if name != canonical_name { + attributes.push(attributes::link_name(name)); + } + + let foreign_item_kind = + ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); + + // Handle overloaded functions by giving each overload its own unique + // suffix. + let times_seen = result.overload_number(&canonical_name); + if times_seen > 0 { + write!(&mut canonical_name, "{}", times_seen).unwrap(); + } + + let foreign_item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attributes, + node: foreign_item_kind, + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(signature.abi() + .expect("Invalid abi for function!")) + .with_foreign_item(foreign_item) + .build(ctx); + + result.push(item); + } +} + + +fn objc_method_codegen(ctx: &BindgenContext, + method: &ObjCMethod, + class_name: Option<&str>) + -> (ast::ImplItem, ast::TraitItem) { + let signature = method.signature(); + let fn_args = utils::fnsig_arguments(ctx, signature); + let fn_ret = utils::fnsig_return_ty(ctx, signature); + + let sig = if method.is_class_method() { + aster::AstBuilder::new() + .method_sig() + .unsafe_() + .fn_decl() + .with_args(fn_args.clone()) + .build(fn_ret) + } else { + aster::AstBuilder::new() + .method_sig() + .unsafe_() + .fn_decl() + .self_() + .build(ast::SelfKind::Value(ast::Mutability::Immutable)) + .with_args(fn_args.clone()) + .build(fn_ret) + }; + + // Collect the actual used argument names + let arg_names: Vec<_> = fn_args.iter() + .map(|ref arg| match arg.pat.node { + ast::PatKind::Ident(_, ref spanning, _) => { + spanning.node.name.as_str().to_string() + } + _ => { + panic!("odd argument!"); + } + }) + .collect(); + + let methods_and_args = + ctx.rust_ident(&method.format_method_call(&arg_names)); + + let body = if method.is_class_method() { + let class_name = + class_name.expect("Generating a class method without class name?") + .to_owned(); + let expect_msg = format!("Couldn't find {}", class_name); + quote_stmt!(ctx.ext_cx(), + msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args]) + .unwrap() + } else { + quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap() + }; + let block = ast::Block { + stmts: vec![body], + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let attrs = vec![]; + + let impl_item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + vis: ast::Visibility::Inherited, // Public, + attrs: attrs.clone(), + node: ast::ImplItemKind::Method(sig.clone(), P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + let trait_item = ast::TraitItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + attrs: attrs, + node: ast::TraitItemKind::Method(sig, None), + span: ctx.span(), + }; + + (impl_item, trait_item) +} + +impl CodeGenerator for ObjCInterface { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + _: &Item) { + let mut impl_items = vec![]; + let mut trait_items = vec![]; + + for method in self.methods() { + let (impl_item, trait_item) = + objc_method_codegen(ctx, method, None); + impl_items.push(impl_item); + trait_items.push(trait_item) + } + + for class_method in self.class_methods() { + let (impl_item, trait_item) = + objc_method_codegen(ctx, class_method, Some(self.name())); + impl_items.push(impl_item); + trait_items.push(trait_item) + } + + let trait_name = self.rust_name(); + + let trait_block = aster::AstBuilder::new() + .item() + .pub_() + .trait_(&trait_name) + .with_items(trait_items) + .build(); + + let ty_for_impl = quote_ty!(ctx.ext_cx(), id); + let impl_block = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id(&trait_name) + .build() + .with_items(impl_items) + .build_ty(ty_for_impl); + + result.push(trait_block); + result.push(impl_block); + result.saw_objc(); + } +} + + + +pub fn codegen(context: &mut BindgenContext) -> Vec> { + context.gen(|context| { + let counter = Cell::new(0); + let mut result = CodegenResult::new(&counter); + + debug!("codegen: {:?}", context.options()); + + let whitelisted_items: ItemSet = context.whitelisted_items().collect(); + + if context.options().emit_ir { + for &id in whitelisted_items.iter() { + let item = context.resolve_item(id); + println!("ir: {:?} = {:#?}", id, item); + } + } + + if let Some(path) = context.options().emit_ir_graphviz.as_ref() { + match dot::write_dot_file(context, path) { + Ok(()) => info!("Your dot file was generated successfully into: {}", path), + Err(e) => error!("{}", e), + } + } + + context.resolve_item(context.root_module()) + .codegen(context, &mut result, &whitelisted_items, &()); + + result.items + }) +} + +mod utils { + use super::{error, TryToRustTy, ToRustTyOrOpaque}; + use aster; + use ir::context::{BindgenContext, ItemId}; + use ir::function::FunctionSig; + use ir::item::{Item, ItemCanonicalPath}; + use ir::ty::TypeKind; + use std::mem; + use syntax::ast; + use syntax::ptr::P; + + pub fn prepend_objc_header(ctx: &BindgenContext, + result: &mut Vec>) { + let use_objc = if ctx.options().objc_extern_crate { + quote_item!(ctx.ext_cx(), + use objc; + ) + .unwrap() + } else { + quote_item!(ctx.ext_cx(), + #[macro_use] + extern crate objc; + ) + .unwrap() + }; + + + let id_type = quote_item!(ctx.ext_cx(), + #[allow(non_camel_case_types)] + pub type id = *mut objc::runtime::Object; + ) + .unwrap(); + + let items = vec![use_objc, id_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_union_types(ctx: &BindgenContext, + result: &mut Vec>) { + let prefix = ctx.trait_prefix(); + + // TODO(emilio): The fmt::Debug impl could be way nicer with + // std::intrinsics::type_name, but... + let union_field_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + pub struct __BindgenUnionField( + ::$prefix::marker::PhantomData); + ) + .unwrap(); + + let union_field_impl = quote_item!(&ctx.ext_cx(), + impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { + __BindgenUnionField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ref(&self) -> &T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + ::$prefix::mem::transmute(self) + } + } + ) + .unwrap(); + + let union_field_default_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_clone_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_copy_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::marker::Copy for __BindgenUnionField {} + ) + .unwrap(); + + let union_field_debug_impl = quote_item!(ctx.ext_cx(), + impl ::$prefix::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) + -> ::$prefix::fmt::Result { + fmt.write_str("__BindgenUnionField") + } + } + ) + .unwrap(); + + let items = vec![union_field_decl, + union_field_impl, + union_field_default_impl, + union_field_clone_impl, + union_field_copy_impl, + union_field_debug_impl]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_incomplete_array_types(ctx: &BindgenContext, + result: &mut Vec>) { + let prefix = ctx.trait_prefix(); + + let incomplete_array_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + #[derive(Default)] + pub struct __IncompleteArrayField( + ::$prefix::marker::PhantomData); + ) + .unwrap(); + + let incomplete_array_impl = quote_item!(&ctx.ext_cx(), + impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::$prefix::slice::from_raw_parts(self.as_ptr(), len) + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + } + ) + .unwrap(); + + let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), + impl ::$prefix::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) + -> ::$prefix::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } + } + ) + .unwrap(); + + let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ) + .unwrap(); + + let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::marker::Copy for __IncompleteArrayField {} + ) + .unwrap(); + + let items = vec![incomplete_array_decl, + incomplete_array_impl, + incomplete_array_debug_impl, + incomplete_array_clone_impl, + incomplete_array_copy_impl]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_complex_type(ctx: &BindgenContext, + result: &mut Vec>) { + let complex_type = quote_item!(ctx.ext_cx(), + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C)] + pub struct __BindgenComplex { + pub re: T, + pub im: T + } + ) + .unwrap(); + + let items = vec![complex_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn build_templated_path(item: &Item, + ctx: &BindgenContext, + template_params: Vec) + -> error::Result> { + let path = item.namespace_aware_canonical_path(ctx); + let builder = aster::AstBuilder::new().ty().path(); + + let template_params = template_params.iter() + .map(|param| param.try_to_rust_ty(ctx, &())) + .collect::>>()?; + + // XXX: I suck at aster. + if path.len() == 1 { + return Ok(builder.segment(&path[0]) + .with_tys(template_params) + .build() + .build()); + } + + let mut builder = builder.id(&path[0]); + for (i, segment) in path.iter().skip(1).enumerate() { + // Take into account the skip(1) + builder = if i == path.len() - 2 { + // XXX Extra clone courtesy of the borrow checker. + builder.segment(&segment) + .with_tys(template_params.clone()) + .build() + } else { + builder.segment(&segment).build() + } + } + + Ok(builder.build()) + } + + fn primitive_ty(ctx: &BindgenContext, name: &str) -> P { + let ident = ctx.rust_ident_raw(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + + pub fn type_from_named(ctx: &BindgenContext, + name: &str, + _inner: ItemId) + -> Option> { + // FIXME: We could use the inner item to check this is really a + // primitive type but, who the heck overrides these anyway? + Some(match name { + "int8_t" => primitive_ty(ctx, "i8"), + "uint8_t" => primitive_ty(ctx, "u8"), + "int16_t" => primitive_ty(ctx, "i16"), + "uint16_t" => primitive_ty(ctx, "u16"), + "int32_t" => primitive_ty(ctx, "i32"), + "uint32_t" => primitive_ty(ctx, "u32"), + "int64_t" => primitive_ty(ctx, "i64"), + "uint64_t" => primitive_ty(ctx, "u64"), + + "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), + + "intptr_t" | "ptrdiff_t" | "ssize_t" => { + primitive_ty(ctx, "isize") + } + _ => return None, + }) + } + + pub fn rust_fndecl_from_signature(ctx: &BindgenContext, + sig: &Item) + -> P { + let signature = sig.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How?"), + }; + + let decl_ty = signature.try_to_rust_ty(ctx, &()) + .expect("function signature to Rust type conversion is infallible"); + match decl_ty.unwrap().node { + ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, + _ => panic!("How did this happen exactly?"), + } + } + + pub fn fnsig_return_ty(ctx: &BindgenContext, + sig: &FunctionSig) + -> ast::FunctionRetTy { + let return_item = ctx.resolve_item(sig.return_type()); + if let TypeKind::Void = *return_item.kind().expect_type().kind() { + ast::FunctionRetTy::Default(ctx.span()) + } else { + ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) + } + } + + pub fn fnsig_arguments(ctx: &BindgenContext, + sig: &FunctionSig) + -> Vec { + use super::ToPtr; + let mut unnamed_arguments = 0; + sig.argument_types().iter().map(|&(ref name, ty)| { + let arg_item = ctx.resolve_item(ty); + let arg_ty = arg_item.kind().expect_type(); + + // From the C90 standard[1]: + // + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + // + // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html + let arg_ty = match *arg_ty.canonical_type(ctx).kind() { + TypeKind::Array(t, _) => { + t.to_rust_ty_or_opaque(ctx, &()) + .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) + }, + TypeKind::Pointer(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { + quote_ty!(ctx.ext_cx(), id) + } else { + arg_item.to_rust_ty_or_opaque(ctx, &()) + } + }, + _ => { + arg_item.to_rust_ty_or_opaque(ctx, &()) + } + }; + + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + + assert!(!arg_name.is_empty()); + + ast::Arg { + ty: arg_ty, + pat: aster::AstBuilder::new().pat().id(arg_name), + id: ast::DUMMY_NODE_ID, + } + }).collect::>() + } +} diff --git a/tests/expectations/tests/anonymous-template-types.rs b/tests/expectations/tests/anonymous-template-types.rs index 50604a3f1b..d5e712dd15 100644 --- a/tests/expectations/tests/anonymous-template-types.rs +++ b/tests/expectations/tests/anonymous-template-types.rs @@ -1,35 +1,35 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t_member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Bar { - pub member: ::std::os::raw::c_char, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Quux { - pub v_member: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Quux { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Lobo { - pub also_member: ::std::os::raw::c_char, -} -pub type AliasWithAnonType = ::std::os::raw::c_char; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t_member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Bar { + pub member: ::std::os::raw::c_char, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Quux { + pub v_member: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Quux { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Lobo { + pub also_member: ::std::os::raw::c_char, +} +pub type AliasWithAnonType = ::std::os::raw::c_char; diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index 8446cbcdf6..60f8633625 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -1,132 +1,132 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub member_a: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_B { - pub member_b: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_B() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_B ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_B ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_B ) , "::" , - stringify ! ( member_b ) )); -} -impl Clone for A_B { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_C { - pub baz: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_C() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_C ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_C ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_C ) , "::" , - stringify ! ( baz ) )); -} -impl Clone for A_C { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct A_D { - pub foo: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for A_D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::
() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , stringify - ! ( member_a ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -extern "C" { - #[link_name = "var"] - pub static mut var: A_B; -} -#[test] -fn __bindgen_test_layout_A_D_instantiation_16() { - assert_eq!(::std::mem::size_of::>() , 4usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 4usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); -} -extern "C" { - #[link_name = "baz"] - pub static mut baz: A_D<::std::os::raw::c_int>; -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct D { - pub member: A_B, -} -#[test] -fn bindgen_test_layout_D() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( D ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( D ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const D ) ) . member as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( D ) , "::" , stringify - ! ( member ) )); -} -impl Clone for D { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated_Templated_inner { - pub member_ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Templated_Templated_inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for Templated { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub member_a: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_B { + pub member_b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_B() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_B ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_B ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_B ) , "::" , + stringify ! ( member_b ) )); +} +impl Clone for A_B { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_C { + pub baz: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_C() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_C ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_C ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_C ) , "::" , + stringify ! ( baz ) )); +} +impl Clone for A_C { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct A_D { + pub foo: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for A_D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , stringify + ! ( member_a ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +extern "C" { + #[link_name = "var"] + pub static mut var: A_B; +} +#[test] +fn __bindgen_test_layout_A_D_instantiation_16() { + assert_eq!(::std::mem::size_of::>() , 4usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 4usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); +} +extern "C" { + #[link_name = "baz"] + pub static mut baz: A_D<::std::os::raw::c_int>; +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct D { + pub member: A_B, +} +#[test] +fn bindgen_test_layout_D() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( D ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( D ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const D ) ) . member as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( D ) , "::" , stringify + ! ( member ) )); +} +impl Clone for D { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated_Templated_inner { + pub member_ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Templated_Templated_inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for Templated { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 3b15b89138..60464cc2a6 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -1,47 +1,47 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct HandleWithDtor { - pub ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for HandleWithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct WithoutDtor { - pub shouldBeWithDtor: HandleValue, -} -#[test] -fn bindgen_test_layout_WithoutDtor() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( WithoutDtor ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( WithoutDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , - stringify ! ( shouldBeWithDtor ) )); -} -impl Default for WithoutDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { - assert_eq!(::std::mem::size_of::>() - , 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() - , 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct HandleWithDtor { + pub ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for HandleWithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct WithoutDtor { + pub shouldBeWithDtor: HandleValue, +} +#[test] +fn bindgen_test_layout_WithoutDtor() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( WithoutDtor ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( WithoutDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , + stringify ! ( shouldBeWithDtor ) )); +} +impl Default for WithoutDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { + assert_eq!(::std::mem::size_of::>() + , 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() + , 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/const_tparam.rs b/tests/expectations/tests/const_tparam.rs index 7600e18eed..aaa89f9c92 100644 --- a/tests/expectations/tests/const_tparam.rs +++ b/tests/expectations/tests/const_tparam.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct C { - pub foo: *const T, - pub bar: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct C { + pub foo: *const T, + pub bar: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/default-template-parameter.rs b/tests/expectations/tests/default-template-parameter.rs index c098dac7b5..70207694a1 100644 --- a/tests/expectations/tests/default-template-parameter.rs +++ b/tests/expectations/tests/default-template-parameter.rs @@ -1,32 +1,32 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t: T, - pub u: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_6() { - assert_eq!(::std::mem::size_of::>() , - 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Foo ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo ) )); -} -extern "C" { - #[link_name = "_ZL3bar"] - pub static mut bar: Foo; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t: T, + pub u: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_6() { + assert_eq!(::std::mem::size_of::>() , + 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Foo ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo ) )); +} +extern "C" { + #[link_name = "_ZL3bar"] + pub static mut bar: Foo; +} diff --git a/tests/expectations/tests/forward-declaration-autoptr.rs b/tests/expectations/tests/forward-declaration-autoptr.rs index 3b5e261618..acd5b535f2 100644 --- a/tests/expectations/tests/forward-declaration-autoptr.rs +++ b/tests/expectations/tests/forward-declaration-autoptr.rs @@ -1,41 +1,41 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo([u8; 0]); -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr { - pub m_inner: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for RefPtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct Bar { - pub m_member: RefPtr, -} -#[test] -fn bindgen_test_layout_Bar() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( Bar ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( Bar ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( Bar ) , "::" , - stringify ! ( m_member ) )); -} -impl Clone for Bar { - fn clone(&self) -> Self { *self } -} -impl Default for Bar { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo([u8; 0]); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr { + pub m_inner: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for RefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Bar { + pub m_member: RefPtr, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( Bar ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( Bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Bar ) , "::" , + stringify ! ( m_member ) )); +} +impl Clone for Bar { + fn clone(&self) -> Self { *self } +} +impl Default for Bar { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/forward-inherit-struct-with-fields.rs b/tests/expectations/tests/forward-inherit-struct-with-fields.rs index 1b31f62b57..4a61631995 100644 --- a/tests/expectations/tests/forward-inherit-struct-with-fields.rs +++ b/tests/expectations/tests/forward-inherit-struct-with-fields.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub _base: js_RootedBase, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct js_RootedBase { - pub foo: *mut T, - pub next: *mut Rooted, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for js_RootedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub _base: js_RootedBase, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct js_RootedBase { + pub foo: *mut T, + pub next: *mut Rooted, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for js_RootedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index a641de70b5..e67a55a76d 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wohoo { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Weeee { - pub _base: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Weeee { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wohoo { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Weeee { + pub _base: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Weeee { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs index ddcaf3fc0b..e83d5800b5 100644 --- a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs +++ b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs @@ -1,81 +1,81 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - -pub type RefPtr = T; - -#[repr(C)] -#[derive(Debug, Copy)] -pub struct b { - pub _base: g, -} -#[test] -fn bindgen_test_layout_b() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( b ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( b ) )); -} -impl Clone for b { - fn clone(&self) -> Self { *self } -} -impl Default for b { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub _address: u8, -} -pub type A_a = b; -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct e { - pub d: RefPtr, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for e { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct f { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct g { - pub h: f, -} -#[test] -fn bindgen_test_layout_g() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( g ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( g ) )); - assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( g ) , "::" , stringify - ! ( h ) )); -} -impl Clone for g { - fn clone(&self) -> Self { *self } -} -impl Default for g { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z25Servo_Element_GetSnapshotv"] - pub fn Servo_Element_GetSnapshot() -> A; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +pub type RefPtr = T; + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct b { + pub _base: g, +} +#[test] +fn bindgen_test_layout_b() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( b ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( b ) )); +} +impl Clone for b { + fn clone(&self) -> Self { *self } +} +impl Default for b { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub _address: u8, +} +pub type A_a = b; +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct e { + pub d: RefPtr, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for e { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct f { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct g { + pub h: f, +} +#[test] +fn bindgen_test_layout_g() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( g ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( g ) )); + assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( g ) , "::" , stringify + ! ( h ) )); +} +impl Clone for g { + fn clone(&self) -> Self { *self } +} +impl Default for g { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z25Servo_Element_GetSnapshotv"] + pub fn Servo_Element_GetSnapshot() -> A; +} diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs index 86d5e89247..7520f03d8d 100644 --- a/tests/expectations/tests/namespace.rs +++ b/tests/expectations/tests/namespace.rs @@ -1,103 +1,103 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - extern "C" { - #[link_name = "_Z9top_levelv"] - pub fn top_level(); - } - pub mod whatever { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_int; - extern "C" { - #[link_name = "_ZN8whatever11in_whateverEv"] - pub fn in_whatever(); - } - } - pub mod _bindgen_mod_id_13 { - #[allow(unused_imports)] - use self::super::super::root; - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_13fooEv"] - pub fn foo(); - } - #[repr(C)] - #[derive(Debug, Default, Copy)] - pub struct A { - pub b: root::whatever::whatever_int_t, - } - #[test] - fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . b as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , - stringify ! ( b ) )); - } - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] - pub fn A_lets_hope_this_works(this: - *mut root::_bindgen_mod_id_13::A) - -> ::std::os::raw::c_int; - } - impl Clone for A { - fn clone(&self) -> Self { *self } - } - impl A { - #[inline] - pub unsafe fn lets_hope_this_works(&mut self) - -> ::std::os::raw::c_int { - A_lets_hope_this_works(self) - } - } - } - #[repr(C)] - #[derive(Debug)] - pub struct C { - pub _base: root::_bindgen_mod_id_13::A, - pub m_c: T, - pub m_c_ptr: *mut T, - pub m_c_arr: [T; 10usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - pub mod w { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_uint; - #[repr(C)] - #[derive(Debug)] - pub struct D { - pub m_c: root::C, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - extern "C" { - #[link_name = "_ZN1w3hehEv"] - pub fn heh() -> root::w::whatever_int_t; - } - extern "C" { - #[link_name = "_ZN1w3fooEv"] - pub fn foo() -> root::C<::std::os::raw::c_int>; - } - extern "C" { - #[link_name = "_ZN1w4barrEv"] - pub fn barr() -> root::C; - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + extern "C" { + #[link_name = "_Z9top_levelv"] + pub fn top_level(); + } + pub mod whatever { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_int; + extern "C" { + #[link_name = "_ZN8whatever11in_whateverEv"] + pub fn in_whatever(); + } + } + pub mod _bindgen_mod_id_13 { + #[allow(unused_imports)] + use self::super::super::root; + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_13fooEv"] + pub fn foo(); + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct A { + pub b: root::whatever::whatever_int_t, + } + #[test] + fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . b as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , + stringify ! ( b ) )); + } + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] + pub fn A_lets_hope_this_works(this: + *mut root::_bindgen_mod_id_13::A) + -> ::std::os::raw::c_int; + } + impl Clone for A { + fn clone(&self) -> Self { *self } + } + impl A { + #[inline] + pub unsafe fn lets_hope_this_works(&mut self) + -> ::std::os::raw::c_int { + A_lets_hope_this_works(self) + } + } + } + #[repr(C)] + #[derive(Debug)] + pub struct C { + pub _base: root::_bindgen_mod_id_13::A, + pub m_c: T, + pub m_c_ptr: *mut T, + pub m_c_arr: [T; 10usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + pub mod w { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug)] + pub struct D { + pub m_c: root::C, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + extern "C" { + #[link_name = "_ZN1w3hehEv"] + pub fn heh() -> root::w::whatever_int_t; + } + extern "C" { + #[link_name = "_ZN1w3fooEv"] + pub fn foo() -> root::C<::std::os::raw::c_int>; + } + extern "C" { + #[link_name = "_ZN1w4barrEv"] + pub fn barr() -> root::C; + } + } +} diff --git a/tests/expectations/tests/nsStyleAutoArray.rs b/tests/expectations/tests/nsStyleAutoArray.rs index 04f01c0c3d..239dfbdd2b 100644 --- a/tests/expectations/tests/nsStyleAutoArray.rs +++ b/tests/expectations/tests/nsStyleAutoArray.rs @@ -1,30 +1,30 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsTArray { - pub mBuff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for nsTArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsStyleAutoArray { - pub mFirstElement: T, - pub mOtherElements: nsTArray, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum nsStyleAutoArray_WithSingleInitialElement { - WITH_SINGLE_INITIAL_ELEMENT = 0, -} -impl Default for nsStyleAutoArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsTArray { + pub mBuff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsTArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsStyleAutoArray { + pub mFirstElement: T, + pub mOtherElements: nsTArray, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum nsStyleAutoArray_WithSingleInitialElement { + WITH_SINGLE_INITIAL_ELEMENT = 0, +} +impl Default for nsStyleAutoArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replace_template_alias.rs b/tests/expectations/tests/replace_template_alias.rs index 65a5332b9a..efe507157b 100644 --- a/tests/expectations/tests/replace_template_alias.rs +++ b/tests/expectations/tests/replace_template_alias.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -/// But the replacement type does use T! -/// -///
-pub type JS_detail_MaybeWrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +/// But the replacement type does use T! +/// +///
+pub type JS_detail_MaybeWrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replaces_double.rs b/tests/expectations/tests/replaces_double.rs index f7093d3d65..4177889385 100644 --- a/tests/expectations/tests/replaces_double.rs +++ b/tests/expectations/tests/replaces_double.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: Rooted_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -/** - *
- */ -pub type Rooted_MaybeWrapped = T; -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: Rooted_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +/** + *
+ */ +pub type Rooted_MaybeWrapped = T; +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs index a36d729a4e..a30d52f9f0 100644 --- a/tests/expectations/tests/template-param-usage-0.rs +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -1,15 +1,15 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs index d41740cd7a..0bfd6ad6e0 100644 --- a/tests/expectations/tests/template-param-usage-10.rs +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage { - pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type DoublyIndirectUsage_Aliased = T; -pub type DoublyIndirectUsage_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage_IndirectUsage { - pub member: DoublyIndirectUsage_Aliased, - pub another: DoublyIndirectUsage_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoublyIndirectUsage_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for DoublyIndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage { + pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type DoublyIndirectUsage_Aliased = T; +pub type DoublyIndirectUsage_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage_IndirectUsage { + pub member: DoublyIndirectUsage_Aliased, + pub another: DoublyIndirectUsage_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoublyIndirectUsage_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for DoublyIndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs index fcf10615f0..c3494b4fc6 100644 --- a/tests/expectations/tests/template-param-usage-12.rs +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub t: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseUsesT>, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub t: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseUsesT>, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs index 10e45ed1f0..d4b52494e9 100644 --- a/tests/expectations/tests/template-param-usage-13.rs +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct BaseIgnoresT { - pub x: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseIgnoresT, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BaseIgnoresT { + pub x: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseIgnoresT, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs index 77667b454f..db48fa3be8 100644 --- a/tests/expectations/tests/template-param-usage-15.rs +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub usage: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpIgnoresU { - pub _base: BaseUsesT, - pub y: ::std::os::raw::c_int, -} -impl Default for CrtpIgnoresU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub usage: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpIgnoresU { + pub _base: BaseUsesT, + pub y: ::std::os::raw::c_int, +} +impl Default for CrtpIgnoresU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs index 4f5987a105..a9ac824b71 100644 --- a/tests/expectations/tests/template-param-usage-2.rs +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { - pub also: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { + pub also: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs index 07571dcc45..c5f40e3842 100644 --- a/tests/expectations/tests/template-param-usage-3.rs +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -1,27 +1,27 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - pub also: T, - pub more: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for - UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + pub also: T, + pub more: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for + UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs index 7b8fe9f1ec..dd6886645c 100644 --- a/tests/expectations/tests/template-param-usage-4.rs +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { - pub x: ::std::os::raw::c_int, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { + pub x: ::std::os::raw::c_int, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs index 3efdfac339..599208d0c3 100644 --- a/tests/expectations/tests/template-param-usage-5.rs +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectlyUsesTemplateParameter { - pub aliased: IndirectlyUsesTemplateParameter_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectlyUsesTemplateParameter_Aliased = T; -impl Default for IndirectlyUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectlyUsesTemplateParameter { + pub aliased: IndirectlyUsesTemplateParameter_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectlyUsesTemplateParameter_Aliased = T; +impl Default for IndirectlyUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs index 3d1378ad98..5f55400cee 100644 --- a/tests/expectations/tests/template-param-usage-7.rs +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUseU { - pub t: T, - pub v: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUseU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUseU { + pub t: T, + pub v: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUseU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs index 322c725718..ee81e2b7bf 100644 --- a/tests/expectations/tests/template-param-usage-8.rs +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectUsage { - pub member1: IndirectUsage_Typedefed, - pub member2: IndirectUsage_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectUsage_Typedefed = T; -pub type IndirectUsage_Aliased = U; -impl Default for IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectUsage { + pub member1: IndirectUsage_Typedefed, + pub member2: IndirectUsage_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectUsage_Typedefed = T; +pub type IndirectUsage_Aliased = U; +impl Default for IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs index 5f2319c448..02a6bd469e 100644 --- a/tests/expectations/tests/template-param-usage-9.rs +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct DoesNotUse { - pub _address: u8, -} -pub type DoesNotUse_Aliased = T; -pub type DoesNotUse_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUse_IndirectUsage { - pub member: DoesNotUse_Aliased, - pub another: DoesNotUse_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUse_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUse { + pub _address: u8, +} +pub type DoesNotUse_Aliased = T; +pub type DoesNotUse_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUse_IndirectUsage { + pub member: DoesNotUse_Aliased, + pub another: DoesNotUse_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUse_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 682c6db9c1..cbabaa99ff 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -1,279 +1,279 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct Foo { - pub m_member: T, - pub m_member_ptr: *mut T, - pub m_member_arr: [T; 1usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z3bar3FooIiiE"] - pub fn bar(foo: Foo<::std::os::raw::c_int>); -} -#[repr(C)] -#[derive(Debug)] -pub struct D { - pub m_foo: D_MyFoo, -} -pub type D_MyFoo = Foo<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct D_U { - pub m_nested_foo: D_MyFoo, - pub m_baz: Z, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for D_U { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub prev: *mut T, - pub next: *mut Rooted<*mut ::std::os::raw::c_void>, - pub ptr: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct RootedContainer { - pub root: Rooted<*mut ::std::os::raw::c_void>, -} -#[test] -fn bindgen_test_layout_RootedContainer() { - assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( - "Size of: " , stringify ! ( RootedContainer ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! - ( "Alignment of " , stringify ! ( RootedContainer ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const RootedContainer ) ) . root as * const _ - as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( RootedContainer ) , - "::" , stringify ! ( root ) )); -} -impl Clone for RootedContainer { - fn clone(&self) -> Self { *self } -} -impl Default for RootedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct WithDtor { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct PODButContainsDtor { - pub member: WithDtorIntFwd, -} -#[test] -fn bindgen_test_layout_PODButContainsDtor() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! - ( "Size of: " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat - ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const PODButContainsDtor ) ) . member as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( PODButContainsDtor ) , - "::" , stringify ! ( member ) )); -} -impl Default for PODButContainsDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/**
*/ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Opaque { -} -impl Default for Opaque { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct POD { - pub opaque_member: u32, -} -#[test] -fn bindgen_test_layout_POD() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( POD ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( POD ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( POD ) , "::" , - stringify ! ( opaque_member ) )); -} -impl Clone for POD { - fn clone(&self) -> Self { *self } -} -/** - *
- */ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedReplaced { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedReplaced { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedBase { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Incomplete { - pub d: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Incomplete { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedContainer { - pub c: T, - pub nested: NestedReplaced, - pub inc: Incomplete, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct Untemplated { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_Untemplated() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( Untemplated ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( Untemplated ) )); -} -impl Clone for Untemplated { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Templated { - pub m_untemplated: Untemplated, -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructor { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiable { - pub m_member: ReplacedWithoutDestructor, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiable { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiableAsWell { - pub m_member: ReplacedWithoutDestructorFwd, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiableAsWell { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructorFwd { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructorFwd { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct TemplateWithVar { - pub _address: u8, -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_95() { - assert_eq!(::std::mem::size_of::>() , 24usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 8usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); -} -#[test] -fn __bindgen_test_layout_Rooted_instantiation_106() { - assert_eq!(::std::mem::size_of::>() , - 24usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); - assert_eq!(::std::mem::align_of::>() , - 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); -} -#[test] -fn __bindgen_test_layout_WithDtor_instantiation_114() { - assert_eq!(::std::mem::size_of::>() , - 4usize , concat ! ( - "Size of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct Foo { + pub m_member: T, + pub m_member_ptr: *mut T, + pub m_member_arr: [T; 1usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z3bar3FooIiiE"] + pub fn bar(foo: Foo<::std::os::raw::c_int>); +} +#[repr(C)] +#[derive(Debug)] +pub struct D { + pub m_foo: D_MyFoo, +} +pub type D_MyFoo = Foo<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct D_U { + pub m_nested_foo: D_MyFoo, + pub m_baz: Z, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for D_U { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub prev: *mut T, + pub next: *mut Rooted<*mut ::std::os::raw::c_void>, + pub ptr: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct RootedContainer { + pub root: Rooted<*mut ::std::os::raw::c_void>, +} +#[test] +fn bindgen_test_layout_RootedContainer() { + assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( + "Size of: " , stringify ! ( RootedContainer ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! + ( "Alignment of " , stringify ! ( RootedContainer ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const RootedContainer ) ) . root as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( RootedContainer ) , + "::" , stringify ! ( root ) )); +} +impl Clone for RootedContainer { + fn clone(&self) -> Self { *self } +} +impl Default for RootedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct WithDtor { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct PODButContainsDtor { + pub member: WithDtorIntFwd, +} +#[test] +fn bindgen_test_layout_PODButContainsDtor() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! + ( "Size of: " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat + ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const PODButContainsDtor ) ) . member as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( PODButContainsDtor ) , + "::" , stringify ! ( member ) )); +} +impl Default for PODButContainsDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/**
*/ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Opaque { +} +impl Default for Opaque { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct POD { + pub opaque_member: u32, +} +#[test] +fn bindgen_test_layout_POD() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( POD ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( POD ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as + usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( POD ) , "::" , + stringify ! ( opaque_member ) )); +} +impl Clone for POD { + fn clone(&self) -> Self { *self } +} +/** + *
+ */ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedReplaced { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedReplaced { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedBase { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Incomplete { + pub d: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Incomplete { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedContainer { + pub c: T, + pub nested: NestedReplaced, + pub inc: Incomplete, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Untemplated { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Untemplated() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( Untemplated ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Untemplated ) )); +} +impl Clone for Untemplated { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Templated { + pub m_untemplated: Untemplated, +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructor { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiable { + pub m_member: ReplacedWithoutDestructor, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiable { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiableAsWell { + pub m_member: ReplacedWithoutDestructorFwd, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiableAsWell { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructorFwd { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructorFwd { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct TemplateWithVar { + pub _address: u8, +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_95() { + assert_eq!(::std::mem::size_of::>() , 24usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 8usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); +} +#[test] +fn __bindgen_test_layout_Rooted_instantiation_106() { + assert_eq!(::std::mem::size_of::>() , + 24usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); + assert_eq!(::std::mem::align_of::>() , + 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); +} +#[test] +fn __bindgen_test_layout_WithDtor_instantiation_114() { + assert_eq!(::std::mem::size_of::>() , + 4usize , concat ! ( + "Size of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/template_alias.rs b/tests/expectations/tests/template_alias.rs index f98d165df8..d0943e94e7 100644 --- a/tests/expectations/tests/template_alias.rs +++ b/tests/expectations/tests/template_alias.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type JS_detail_Wrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type JS_detail_Wrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template_alias_namespace.rs b/tests/expectations/tests/template_alias_namespace.rs index 491bb68cad..ff6a8dc0d2 100644 --- a/tests/expectations/tests/template_alias_namespace.rs +++ b/tests/expectations/tests/template_alias_namespace.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - pub mod JS { - #[allow(unused_imports)] - use self::super::super::root; - pub mod detail { - #[allow(unused_imports)] - use self::super::super::super::root; - pub type Wrapped = T; - } - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct Rooted { - pub ptr: root::JS::detail::Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod JS { + #[allow(unused_imports)] + use self::super::super::root; + pub mod detail { + #[allow(unused_imports)] + use self::super::super::super::root; + pub type Wrapped = T; + } + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct Rooted { + pub ptr: root::JS::detail::Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + } +} diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index 5f6b4c38db..f98100314a 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wrapper { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Wrapper_Wrapped { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Wrapper_Wrapped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Wrapper_Type = Wrapper_Wrapped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wrapper { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Wrapper_Wrapped { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Wrapper_Wrapped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Wrapper_Type = Wrapper_Wrapped; diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs index 09c3248621..4f0c2dc8f7 100644 --- a/tests/expectations/tests/type_alias_partial_template_especialization.rs +++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type MaybeWrapped
= A; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type MaybeWrapped = A; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/using.rs b/tests/expectations/tests/using.rs index 44376b93a9..58a981bcff 100644 --- a/tests/expectations/tests/using.rs +++ b/tests/expectations/tests/using.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Point { - pub x: T, - pub y: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Point { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint2D = Point<::std::os::raw::c_int>; -pub type IntVec2D = Point<::std::os::raw::c_int>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Point { + pub x: T, + pub y: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Point { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint2D = Point<::std::os::raw::c_int>; +pub type IntVec2D = Point<::std::os::raw::c_int>; diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index fa56f04b6d..f96c4b9254 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -1,33 +1,33 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct UnknownUnits { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_UnknownUnits() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( UnknownUnits ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( UnknownUnits ) )); -} -impl Clone for UnknownUnits { - fn clone(&self) -> Self { *self } -} -pub type Float = f32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PointTyped { - pub x: F, - pub y: F, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for PointTyped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint = PointTyped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct UnknownUnits { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_UnknownUnits() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( UnknownUnits ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( UnknownUnits ) )); +} +impl Clone for UnknownUnits { + fn clone(&self) -> Self { *self } +} +pub type Float = f32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PointTyped { + pub x: F, + pub y: F, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for PointTyped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint = PointTyped; diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index a83f02735b..6d4377de4a 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe { - pub foo: ::std::os::raw::c_int, - pub bar: WhitelistMe_Inner, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe_Inner { - pub bar: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WhitelistMe_Inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for WhitelistMe { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe { + pub foo: ::std::os::raw::c_int, + pub bar: WhitelistMe_Inner, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe_Inner { + pub bar: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WhitelistMe_Inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for WhitelistMe { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/stylo_sanity.rs b/tests/stylo_sanity.rs index e5bfd1c219..c75d65a4c2 100755 --- a/tests/stylo_sanity.rs +++ b/tests/stylo_sanity.rs @@ -1,548 +1,548 @@ -extern crate bindgen; - -/// A sanity test that we can generate bindings for Stylo. -/// -/// We don't assert on expected output because its just too big. The output will -/// change too often, and it won't be clear what is going on at a glance, unlike -/// the other tests with smaller input headers. -/// -/// This test is relatively slow, so we also only run it in release mode. -/// -/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing -/// how long bindings generation takes for Stylo. Stylo bindings generation -/// takes too long to be a proper `#[bench]`. -#[test] -#[cfg(not(any(debug_assertions, - feature = "testing_only_extra_assertions", - feature = "testing_only_llvm_stable")))] -fn sanity_check_can_generate_stylo_bindings() { - use std::time::Instant; - - let then = Instant::now(); - - bindgen::builder() - .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) - .whitelisted_function("Servo_.*") - .whitelisted_function("Gecko_.*") - .hide_type("nsACString_internal") - .hide_type("nsAString_internal") - .hide_type("mozilla::css::URLValue") - .hide_type("RawGeckoAnimationPropertySegment") - .hide_type("RawGeckoComputedTiming") - .hide_type("RawGeckoDocument") - .hide_type("RawGeckoElement") - .hide_type("RawGeckoKeyframeList") - .hide_type("RawGeckoComputedKeyframeValuesList") - .hide_type("RawGeckoFontFaceRuleList") - .hide_type("RawGeckoNode") - .hide_type("RawGeckoAnimationValueList") - .hide_type("RawServoAnimationValue") - .hide_type("RawServoAnimationValueMap") - .hide_type("RawServoDeclarationBlock") - .hide_type("RawGeckoPresContext") - .hide_type("RawGeckoPresContextOwned") - .hide_type("RawGeckoStyleAnimationList") - .hide_type("RawGeckoURLExtraData") - .hide_type("RefPtr") - .hide_type("CSSPseudoClassType") - .hide_type("TraversalRootBehavior") - .hide_type("ComputedTimingFunction_BeforeFlag") - .hide_type("FontFamilyList") - .hide_type("FontFamilyType") - .hide_type("Keyframe") - .hide_type("ServoBundledURI") - .hide_type("ServoElementSnapshot") - .hide_type("SheetParsingMode") - .hide_type("StyleBasicShape") - .hide_type("StyleBasicShapeType") - .hide_type("StyleShapeSource") - .hide_type("nsCSSFontFaceRule") - .hide_type("nsCSSKeyword") - .hide_type("nsCSSPropertyID") - .hide_type("nsCSSShadowArray") - .hide_type("nsCSSUnit") - .hide_type("nsCSSValue") - .hide_type("nsCSSValueSharedList") - .hide_type("nsChangeHint") - .hide_type("nsCursorImage") - .hide_type("nsFont") - .hide_type("nsIAtom") - .hide_type("nsMediaFeature") - .hide_type("nsRestyleHint") - .hide_type("nsStyleBackground") - .hide_type("nsStyleBorder") - .hide_type("nsStyleColor") - .hide_type("nsStyleColumn") - .hide_type("nsStyleContent") - .hide_type("nsStyleContentData") - .hide_type("nsStyleContentType") - .hide_type("nsStyleContext") - .hide_type("nsStyleCoord") - .hide_type("nsStyleCoord_Calc") - .hide_type("nsStyleCoord_CalcValue") - .hide_type("nsStyleDisplay") - .hide_type("nsStyleEffects") - .hide_type("nsStyleFilter") - .hide_type("nsStyleFont") - .hide_type("nsStyleGradient") - .hide_type("nsStyleGradientStop") - .hide_type("nsStyleImage") - .hide_type("nsStyleImageLayers") - .hide_type("nsStyleImageLayers_Layer") - .hide_type("nsStyleImageLayers_LayerType") - .hide_type("nsStyleImageRequest") - .hide_type("nsStyleList") - .hide_type("nsStyleMargin") - .hide_type("nsStyleOutline") - .hide_type("nsStylePadding") - .hide_type("nsStylePosition") - .hide_type("nsStyleQuoteValues") - .hide_type("nsStyleSVG") - .hide_type("nsStyleSVGPaint") - .hide_type("nsStyleSVGReset") - .hide_type("nsStyleTable") - .hide_type("nsStyleTableBorder") - .hide_type("nsStyleText") - .hide_type("nsStyleTextReset") - .hide_type("nsStyleUIReset") - .hide_type("nsStyleUnion") - .hide_type("nsStyleUnit") - .hide_type("nsStyleUserInterface") - .hide_type("nsStyleVariables") - .hide_type("nsStyleVisibility") - .hide_type("nsStyleXUL") - .hide_type("nsTimingFunction") - .hide_type("nscolor") - .hide_type("nscoord") - .hide_type("nsresult") - .hide_type("Loader") - .hide_type("ServoStyleSheet") - .hide_type("EffectCompositor_CascadeLevel") - .hide_type("UpdateAnimationsTasks") - .hide_type("nsTArrayBorrowed_uintptr_t") - .hide_type("ServoCssRulesStrong") - .hide_type("ServoCssRulesBorrowed") - .hide_type("ServoCssRulesBorrowedOrNull") - .hide_type("ServoCssRules") - .hide_type("RawServoStyleSheetStrong") - .hide_type("RawServoStyleSheetBorrowed") - .hide_type("RawServoStyleSheetBorrowedOrNull") - .hide_type("RawServoStyleSheet") - .hide_type("ServoComputedValuesStrong") - .hide_type("ServoComputedValuesBorrowed") - .hide_type("ServoComputedValuesBorrowedOrNull") - .hide_type("ServoComputedValues") - .hide_type("RawServoDeclarationBlockStrong") - .hide_type("RawServoDeclarationBlockBorrowed") - .hide_type("RawServoDeclarationBlockBorrowedOrNull") - .hide_type("RawServoStyleRuleStrong") - .hide_type("RawServoStyleRuleBorrowed") - .hide_type("RawServoStyleRuleBorrowedOrNull") - .hide_type("RawServoStyleRule") - .hide_type("RawServoImportRuleStrong") - .hide_type("RawServoImportRuleBorrowed") - .hide_type("RawServoImportRuleBorrowedOrNull") - .hide_type("RawServoImportRule") - .hide_type("RawServoAnimationValueStrong") - .hide_type("RawServoAnimationValueBorrowed") - .hide_type("RawServoAnimationValueBorrowedOrNull") - .hide_type("RawServoAnimationValueMapStrong") - .hide_type("RawServoAnimationValueMapBorrowed") - .hide_type("RawServoAnimationValueMapBorrowedOrNull") - .hide_type("RawServoMediaListStrong") - .hide_type("RawServoMediaListBorrowed") - .hide_type("RawServoMediaListBorrowedOrNull") - .hide_type("RawServoMediaList") - .hide_type("RawServoMediaRuleStrong") - .hide_type("RawServoMediaRuleBorrowed") - .hide_type("RawServoMediaRuleBorrowedOrNull") - .hide_type("RawServoMediaRule") - .hide_type("RawServoNamespaceRuleStrong") - .hide_type("RawServoNamespaceRuleBorrowed") - .hide_type("RawServoNamespaceRuleBorrowedOrNull") - .hide_type("RawServoNamespaceRule") - .hide_type("RawServoStyleSetOwned") - .hide_type("RawServoStyleSetOwnedOrNull") - .hide_type("RawServoStyleSetBorrowed") - .hide_type("RawServoStyleSetBorrowedOrNull") - .hide_type("RawServoStyleSetBorrowedMut") - .hide_type("RawServoStyleSetBorrowedMutOrNull") - .hide_type("RawServoStyleSet") - .hide_type("StyleChildrenIteratorOwned") - .hide_type("StyleChildrenIteratorOwnedOrNull") - .hide_type("StyleChildrenIteratorBorrowed") - .hide_type("StyleChildrenIteratorBorrowedOrNull") - .hide_type("StyleChildrenIteratorBorrowedMut") - .hide_type("StyleChildrenIteratorBorrowedMutOrNull") - .hide_type("StyleChildrenIterator") - .hide_type("ServoElementSnapshotOwned") - .hide_type("ServoElementSnapshotOwnedOrNull") - .hide_type("ServoElementSnapshotBorrowed") - .hide_type("ServoElementSnapshotBorrowedOrNull") - .hide_type("ServoElementSnapshotBorrowedMut") - .hide_type("ServoElementSnapshotBorrowedMutOrNull") - .hide_type("RawGeckoNodeBorrowed") - .hide_type("RawGeckoNodeBorrowedOrNull") - .hide_type("RawGeckoElementBorrowed") - .hide_type("RawGeckoElementBorrowedOrNull") - .hide_type("RawGeckoDocumentBorrowed") - .hide_type("RawGeckoDocumentBorrowedOrNull") - .hide_type("RawServoDeclarationBlockStrongBorrowed") - .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") - .hide_type("RawGeckoPresContextBorrowed") - .hide_type("RawGeckoPresContextBorrowedOrNull") - .hide_type("RawGeckoStyleAnimationListBorrowed") - .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") - .hide_type("nsCSSValueBorrowed") - .hide_type("nsCSSValueBorrowedOrNull") - .hide_type("nsCSSValueBorrowedMut") - .hide_type("nsCSSValueBorrowedMutOrNull") - .hide_type("nsTimingFunctionBorrowed") - .hide_type("nsTimingFunctionBorrowedOrNull") - .hide_type("nsTimingFunctionBorrowedMut") - .hide_type("nsTimingFunctionBorrowedMutOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowed") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") - .hide_type("RawGeckoAnimationValueListBorrowed") - .hide_type("RawGeckoAnimationValueListBorrowedOrNull") - .hide_type("RawGeckoAnimationValueListBorrowedMut") - .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") - .hide_type("RawGeckoComputedTimingBorrowed") - .hide_type("RawGeckoComputedTimingBorrowedOrNull") - .hide_type("RawGeckoComputedTimingBorrowedMut") - .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") - .hide_type("RawGeckoKeyframeListBorrowed") - .hide_type("RawGeckoKeyframeListBorrowedOrNull") - .hide_type("RawGeckoKeyframeListBorrowedMut") - .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowed") - .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowedMut") - .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") - .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) - .raw_line(r#"type nsACString_internal = nsACString;"#) - .raw_line(r#"type nsAString_internal = nsAString;"#) - .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) - .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) - .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) - .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) - .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) - .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) - .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) - .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) - .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) - .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) - .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) - .raw_line(r#"use gecko_bindings::structs::nsFont;"#) - .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) - .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) - .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) - .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) - .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) - .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) - .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) - .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) - .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) - .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) - .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) - .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) - .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) - .raw_line(r#"unsafe impl Send for nsStyleList {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) - .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) - .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) - .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) - .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) - .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) - .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) - .raw_line(r#"unsafe impl Send for nsStyleText {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) - .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) - .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) - .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) - .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) - .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) - .raw_line(r#"use gecko_bindings::structs::nscolor;"#) - .raw_line(r#"use gecko_bindings::structs::nscoord;"#) - .raw_line(r#"use gecko_bindings::structs::nsresult;"#) - .raw_line(r#"use gecko_bindings::structs::Loader;"#) - .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) - .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) - .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) - .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) - .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) - .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) - .raw_line(r#"enum ServoCssRulesVoid { }"#) - .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) - .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) - .raw_line(r#"enum RawServoStyleSheetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) - .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) - .raw_line(r#"enum ServoComputedValuesVoid { }"#) - .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) - .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) - .raw_line(r#"enum RawServoStyleRuleVoid { }"#) - .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) - .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) - .raw_line(r#"enum RawServoImportRuleVoid { }"#) - .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) - .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) - .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) - .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) - .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) - .raw_line(r#"enum RawServoMediaListVoid { }"#) - .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) - .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) - .raw_line(r#"enum RawServoMediaRuleVoid { }"#) - .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) - .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) - .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) - .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) - .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) - .raw_line(r#"enum RawServoStyleSetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) - .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) - .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) - .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) - .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) - .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) - .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) - .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("-std=c++14") - .clang_arg("-DTRACING=1") - .clang_arg("-DIMPL_LIBXUL") - .clang_arg("-DMOZ_STYLO_BINDINGS=1") - .clang_arg("-DMOZILLA_INTERNAL_API") - .clang_arg("-DRUST_BINDGEN") - .clang_arg("-DMOZ_STYLO") - .clang_arg("-DOS_POSIX=1") - .clang_arg("-DOS_LINUX=1") - .generate() - .expect("Should generate stylo bindings"); - - let now = Instant::now(); - - println!(""); - println!(""); - println!("Generated Stylo bindings in: {:?}", - now.duration_since(then)); - println!(""); - println!(""); - - // panic!("Uncomment this line to get timing logs"); -} +extern crate bindgen; + +/// A sanity test that we can generate bindings for Stylo. +/// +/// We don't assert on expected output because its just too big. The output will +/// change too often, and it won't be clear what is going on at a glance, unlike +/// the other tests with smaller input headers. +/// +/// This test is relatively slow, so we also only run it in release mode. +/// +/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing +/// how long bindings generation takes for Stylo. Stylo bindings generation +/// takes too long to be a proper `#[bench]`. +#[test] +#[cfg(not(any(debug_assertions, + feature = "testing_only_extra_assertions", + feature = "testing_only_llvm_stable")))] +fn sanity_check_can_generate_stylo_bindings() { + use std::time::Instant; + + let then = Instant::now(); + + bindgen::builder() + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) + .whitelisted_function("Servo_.*") + .whitelisted_function("Gecko_.*") + .hide_type("nsACString_internal") + .hide_type("nsAString_internal") + .hide_type("mozilla::css::URLValue") + .hide_type("RawGeckoAnimationPropertySegment") + .hide_type("RawGeckoComputedTiming") + .hide_type("RawGeckoDocument") + .hide_type("RawGeckoElement") + .hide_type("RawGeckoKeyframeList") + .hide_type("RawGeckoComputedKeyframeValuesList") + .hide_type("RawGeckoFontFaceRuleList") + .hide_type("RawGeckoNode") + .hide_type("RawGeckoAnimationValueList") + .hide_type("RawServoAnimationValue") + .hide_type("RawServoAnimationValueMap") + .hide_type("RawServoDeclarationBlock") + .hide_type("RawGeckoPresContext") + .hide_type("RawGeckoPresContextOwned") + .hide_type("RawGeckoStyleAnimationList") + .hide_type("RawGeckoURLExtraData") + .hide_type("RefPtr") + .hide_type("CSSPseudoClassType") + .hide_type("TraversalRootBehavior") + .hide_type("ComputedTimingFunction_BeforeFlag") + .hide_type("FontFamilyList") + .hide_type("FontFamilyType") + .hide_type("Keyframe") + .hide_type("ServoBundledURI") + .hide_type("ServoElementSnapshot") + .hide_type("SheetParsingMode") + .hide_type("StyleBasicShape") + .hide_type("StyleBasicShapeType") + .hide_type("StyleShapeSource") + .hide_type("nsCSSFontFaceRule") + .hide_type("nsCSSKeyword") + .hide_type("nsCSSPropertyID") + .hide_type("nsCSSShadowArray") + .hide_type("nsCSSUnit") + .hide_type("nsCSSValue") + .hide_type("nsCSSValueSharedList") + .hide_type("nsChangeHint") + .hide_type("nsCursorImage") + .hide_type("nsFont") + .hide_type("nsIAtom") + .hide_type("nsMediaFeature") + .hide_type("nsRestyleHint") + .hide_type("nsStyleBackground") + .hide_type("nsStyleBorder") + .hide_type("nsStyleColor") + .hide_type("nsStyleColumn") + .hide_type("nsStyleContent") + .hide_type("nsStyleContentData") + .hide_type("nsStyleContentType") + .hide_type("nsStyleContext") + .hide_type("nsStyleCoord") + .hide_type("nsStyleCoord_Calc") + .hide_type("nsStyleCoord_CalcValue") + .hide_type("nsStyleDisplay") + .hide_type("nsStyleEffects") + .hide_type("nsStyleFilter") + .hide_type("nsStyleFont") + .hide_type("nsStyleGradient") + .hide_type("nsStyleGradientStop") + .hide_type("nsStyleImage") + .hide_type("nsStyleImageLayers") + .hide_type("nsStyleImageLayers_Layer") + .hide_type("nsStyleImageLayers_LayerType") + .hide_type("nsStyleImageRequest") + .hide_type("nsStyleList") + .hide_type("nsStyleMargin") + .hide_type("nsStyleOutline") + .hide_type("nsStylePadding") + .hide_type("nsStylePosition") + .hide_type("nsStyleQuoteValues") + .hide_type("nsStyleSVG") + .hide_type("nsStyleSVGPaint") + .hide_type("nsStyleSVGReset") + .hide_type("nsStyleTable") + .hide_type("nsStyleTableBorder") + .hide_type("nsStyleText") + .hide_type("nsStyleTextReset") + .hide_type("nsStyleUIReset") + .hide_type("nsStyleUnion") + .hide_type("nsStyleUnit") + .hide_type("nsStyleUserInterface") + .hide_type("nsStyleVariables") + .hide_type("nsStyleVisibility") + .hide_type("nsStyleXUL") + .hide_type("nsTimingFunction") + .hide_type("nscolor") + .hide_type("nscoord") + .hide_type("nsresult") + .hide_type("Loader") + .hide_type("ServoStyleSheet") + .hide_type("EffectCompositor_CascadeLevel") + .hide_type("UpdateAnimationsTasks") + .hide_type("nsTArrayBorrowed_uintptr_t") + .hide_type("ServoCssRulesStrong") + .hide_type("ServoCssRulesBorrowed") + .hide_type("ServoCssRulesBorrowedOrNull") + .hide_type("ServoCssRules") + .hide_type("RawServoStyleSheetStrong") + .hide_type("RawServoStyleSheetBorrowed") + .hide_type("RawServoStyleSheetBorrowedOrNull") + .hide_type("RawServoStyleSheet") + .hide_type("ServoComputedValuesStrong") + .hide_type("ServoComputedValuesBorrowed") + .hide_type("ServoComputedValuesBorrowedOrNull") + .hide_type("ServoComputedValues") + .hide_type("RawServoDeclarationBlockStrong") + .hide_type("RawServoDeclarationBlockBorrowed") + .hide_type("RawServoDeclarationBlockBorrowedOrNull") + .hide_type("RawServoStyleRuleStrong") + .hide_type("RawServoStyleRuleBorrowed") + .hide_type("RawServoStyleRuleBorrowedOrNull") + .hide_type("RawServoStyleRule") + .hide_type("RawServoImportRuleStrong") + .hide_type("RawServoImportRuleBorrowed") + .hide_type("RawServoImportRuleBorrowedOrNull") + .hide_type("RawServoImportRule") + .hide_type("RawServoAnimationValueStrong") + .hide_type("RawServoAnimationValueBorrowed") + .hide_type("RawServoAnimationValueBorrowedOrNull") + .hide_type("RawServoAnimationValueMapStrong") + .hide_type("RawServoAnimationValueMapBorrowed") + .hide_type("RawServoAnimationValueMapBorrowedOrNull") + .hide_type("RawServoMediaListStrong") + .hide_type("RawServoMediaListBorrowed") + .hide_type("RawServoMediaListBorrowedOrNull") + .hide_type("RawServoMediaList") + .hide_type("RawServoMediaRuleStrong") + .hide_type("RawServoMediaRuleBorrowed") + .hide_type("RawServoMediaRuleBorrowedOrNull") + .hide_type("RawServoMediaRule") + .hide_type("RawServoNamespaceRuleStrong") + .hide_type("RawServoNamespaceRuleBorrowed") + .hide_type("RawServoNamespaceRuleBorrowedOrNull") + .hide_type("RawServoNamespaceRule") + .hide_type("RawServoStyleSetOwned") + .hide_type("RawServoStyleSetOwnedOrNull") + .hide_type("RawServoStyleSetBorrowed") + .hide_type("RawServoStyleSetBorrowedOrNull") + .hide_type("RawServoStyleSetBorrowedMut") + .hide_type("RawServoStyleSetBorrowedMutOrNull") + .hide_type("RawServoStyleSet") + .hide_type("StyleChildrenIteratorOwned") + .hide_type("StyleChildrenIteratorOwnedOrNull") + .hide_type("StyleChildrenIteratorBorrowed") + .hide_type("StyleChildrenIteratorBorrowedOrNull") + .hide_type("StyleChildrenIteratorBorrowedMut") + .hide_type("StyleChildrenIteratorBorrowedMutOrNull") + .hide_type("StyleChildrenIterator") + .hide_type("ServoElementSnapshotOwned") + .hide_type("ServoElementSnapshotOwnedOrNull") + .hide_type("ServoElementSnapshotBorrowed") + .hide_type("ServoElementSnapshotBorrowedOrNull") + .hide_type("ServoElementSnapshotBorrowedMut") + .hide_type("ServoElementSnapshotBorrowedMutOrNull") + .hide_type("RawGeckoNodeBorrowed") + .hide_type("RawGeckoNodeBorrowedOrNull") + .hide_type("RawGeckoElementBorrowed") + .hide_type("RawGeckoElementBorrowedOrNull") + .hide_type("RawGeckoDocumentBorrowed") + .hide_type("RawGeckoDocumentBorrowedOrNull") + .hide_type("RawServoDeclarationBlockStrongBorrowed") + .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") + .hide_type("RawGeckoPresContextBorrowed") + .hide_type("RawGeckoPresContextBorrowedOrNull") + .hide_type("RawGeckoStyleAnimationListBorrowed") + .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") + .hide_type("nsCSSValueBorrowed") + .hide_type("nsCSSValueBorrowedOrNull") + .hide_type("nsCSSValueBorrowedMut") + .hide_type("nsCSSValueBorrowedMutOrNull") + .hide_type("nsTimingFunctionBorrowed") + .hide_type("nsTimingFunctionBorrowedOrNull") + .hide_type("nsTimingFunctionBorrowedMut") + .hide_type("nsTimingFunctionBorrowedMutOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowed") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") + .hide_type("RawGeckoAnimationValueListBorrowed") + .hide_type("RawGeckoAnimationValueListBorrowedOrNull") + .hide_type("RawGeckoAnimationValueListBorrowedMut") + .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") + .hide_type("RawGeckoComputedTimingBorrowed") + .hide_type("RawGeckoComputedTimingBorrowedOrNull") + .hide_type("RawGeckoComputedTimingBorrowedMut") + .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") + .hide_type("RawGeckoKeyframeListBorrowed") + .hide_type("RawGeckoKeyframeListBorrowedOrNull") + .hide_type("RawGeckoKeyframeListBorrowedMut") + .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowed") + .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowedMut") + .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") + .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) + .raw_line(r#"type nsACString_internal = nsACString;"#) + .raw_line(r#"type nsAString_internal = nsAString;"#) + .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) + .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) + .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) + .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) + .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) + .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) + .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) + .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) + .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) + .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) + .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) + .raw_line(r#"use gecko_bindings::structs::nsFont;"#) + .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) + .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) + .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) + .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) + .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) + .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) + .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) + .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) + .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) + .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) + .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) + .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) + .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) + .raw_line(r#"unsafe impl Send for nsStyleList {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) + .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) + .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) + .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) + .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) + .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) + .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) + .raw_line(r#"unsafe impl Send for nsStyleText {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) + .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) + .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) + .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) + .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) + .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) + .raw_line(r#"use gecko_bindings::structs::nscolor;"#) + .raw_line(r#"use gecko_bindings::structs::nscoord;"#) + .raw_line(r#"use gecko_bindings::structs::nsresult;"#) + .raw_line(r#"use gecko_bindings::structs::Loader;"#) + .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) + .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) + .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) + .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) + .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) + .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) + .raw_line(r#"enum ServoCssRulesVoid { }"#) + .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) + .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) + .raw_line(r#"enum RawServoStyleSheetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) + .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) + .raw_line(r#"enum ServoComputedValuesVoid { }"#) + .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) + .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) + .raw_line(r#"enum RawServoStyleRuleVoid { }"#) + .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) + .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) + .raw_line(r#"enum RawServoImportRuleVoid { }"#) + .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) + .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) + .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) + .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) + .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) + .raw_line(r#"enum RawServoMediaListVoid { }"#) + .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) + .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) + .raw_line(r#"enum RawServoMediaRuleVoid { }"#) + .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) + .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) + .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) + .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) + .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) + .raw_line(r#"enum RawServoStyleSetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) + .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) + .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) + .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) + .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) + .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) + .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) + .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) + .clang_arg("-x") + .clang_arg("c++") + .clang_arg("-std=c++14") + .clang_arg("-DTRACING=1") + .clang_arg("-DIMPL_LIBXUL") + .clang_arg("-DMOZ_STYLO_BINDINGS=1") + .clang_arg("-DMOZILLA_INTERNAL_API") + .clang_arg("-DRUST_BINDGEN") + .clang_arg("-DMOZ_STYLO") + .clang_arg("-DOS_POSIX=1") + .clang_arg("-DOS_LINUX=1") + .generate() + .expect("Should generate stylo bindings"); + + let now = Instant::now(); + + println!(""); + println!(""); + println!("Generated Stylo bindings in: {:?}", + now.duration_since(then)); + println!(""); + println!(""); + + // panic!("Uncomment this line to get timing logs"); +} diff --git a/tests/tests.rs b/tests/tests.rs index 8b017b54c8..84506aa05d 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,171 +1,171 @@ -extern crate clap; -extern crate diff; -extern crate bindgen; -extern crate shlex; - -use bindgen::{Builder, builder}; -use std::fs; -use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; -use std::path::PathBuf; - -#[path="../src/options.rs"] -mod options; -use options::builder_from_flags; - -fn compare_generated_header(header: &PathBuf, - builder: Builder) - -> Result<(), Error> { - let file_name = - try!(header - .file_name() - .ok_or(Error::new(ErrorKind::Other, - "spawn_bindgen expects a file"))); - - let mut expected = PathBuf::from(header); - expected.pop(); - expected.pop(); - expected.push("expectations"); - expected.push("tests"); - expected.push(file_name); - expected.set_extension("rs"); - - // We skip the generate() error here so we get a full diff below - let output = match builder.generate() { - Ok(bindings) => bindings.to_string(), - Err(_) => "".to_string(), - }; - - let mut buffer = String::new(); - { - if let Ok(expected_file) = fs::File::open(&expected) { - try!(BufReader::new(expected_file).read_to_string(&mut buffer)); - } - } - - if output == buffer { - if !output.is_empty() { - return Ok(()); - } - return Err(Error::new(ErrorKind::Other, - "Something's gone really wrong!")); - } - - println!("diff expected generated"); - println!("--- expected: {:?}", expected); - println!("+++ generated from: {:?}", header); - - for diff in diff::lines(&buffer, &output) { - match diff { - diff::Result::Left(l) => println!("-{}", l), - diff::Result::Both(l, _) => println!(" {}", l), - diff::Result::Right(r) => println!("+{}", r), - } - } - - // Override the diff. - { - let mut expected_file = try!(fs::File::create(&expected)); - try!(expected_file.write_all(output.as_bytes())); - } - - Err(Error::new(ErrorKind::Other, "Header and binding differ!")) -} - -fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { - let source = try!(fs::File::open(header)); - let reader = BufReader::new(source); - - // Scoop up bindgen-flags from test header - let mut flags = Vec::with_capacity(2); - - for line in reader.lines().take(3) { - let line = try!(line); - if line.contains("bindgen-flags: ") { - let extra_flags = line.split("bindgen-flags: ") - .last() - .and_then(shlex::split) - .unwrap(); - flags.extend(extra_flags.into_iter()); - } else if line.contains("bindgen-unstable") && - cfg!(feature = "testing_only_llvm_stable") { - return Ok(None); - } else if line.contains("bindgen-osx-only") { - let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; - flags = prepend_flags - .into_iter() - .map(ToString::to_string) - .chain(flags) - .collect(); - } - } - - // Fool builder_from_flags() into believing it has real env::args_os... - // - add "bindgen" as executable name 0th element - // - add header filename as 1st element - // - prepend raw lines so they're in the right order for expected output - // - append the test header's bindgen flags - let header_str = try!(header - .to_str() - .ok_or(Error::new(ErrorKind::Other, - "Invalid header file name"))); - - let prepend = ["bindgen", - "--with-derive-default", - header_str, - "--raw-line", - "", - "--raw-line", - "#![allow(non_snake_case)]", - "--raw-line", - ""]; - - let args = prepend - .into_iter() - .map(ToString::to_string) - .chain(flags.into_iter()); - - builder_from_flags(args).map(|(builder, _, _)| { - Some(builder.no_unstable_rust()) - }) -} - -macro_rules! test_header { - ($function:ident, $header:expr) => ( - #[test] - fn $function() { - let header = PathBuf::from($header); - let result = create_bindgen_builder(&header) - .and_then(|builder| { - if let Some(builder) = builder { - compare_generated_header(&header, builder) - } else { - Ok(()) - } - }); - - if let Err(err) = result { - panic!("{}", err); - } - } - ) -} - -// This file is generated by build.rs -include!(concat!(env!("OUT_DIR"), "/tests.rs")); - -#[test] -fn test_header_contents() { - let bindings = builder() - .header_contents("test.h", "int foo(const char* a);") - .no_unstable_rust() - .generate() - .unwrap() - .to_string(); - assert_eq!(bindings, - "/* automatically generated by rust-bindgen */ - -extern \"C\" { - pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -"); -} +extern crate clap; +extern crate diff; +extern crate bindgen; +extern crate shlex; + +use bindgen::{Builder, builder}; +use std::fs; +use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; +use std::path::PathBuf; + +#[path="../src/options.rs"] +mod options; +use options::builder_from_flags; + +fn compare_generated_header(header: &PathBuf, + builder: Builder) + -> Result<(), Error> { + let file_name = + try!(header + .file_name() + .ok_or(Error::new(ErrorKind::Other, + "spawn_bindgen expects a file"))); + + let mut expected = PathBuf::from(header); + expected.pop(); + expected.pop(); + expected.push("expectations"); + expected.push("tests"); + expected.push(file_name); + expected.set_extension("rs"); + + // We skip the generate() error here so we get a full diff below + let output = match builder.generate() { + Ok(bindings) => bindings.to_string(), + Err(_) => "".to_string(), + }; + + let mut buffer = String::new(); + { + if let Ok(expected_file) = fs::File::open(&expected) { + try!(BufReader::new(expected_file).read_to_string(&mut buffer)); + } + } + + if output == buffer { + if !output.is_empty() { + return Ok(()); + } + return Err(Error::new(ErrorKind::Other, + "Something's gone really wrong!")); + } + + println!("diff expected generated"); + println!("--- expected: {:?}", expected); + println!("+++ generated from: {:?}", header); + + for diff in diff::lines(&buffer, &output) { + match diff { + diff::Result::Left(l) => println!("-{}", l), + diff::Result::Both(l, _) => println!(" {}", l), + diff::Result::Right(r) => println!("+{}", r), + } + } + + // Override the diff. + { + let mut expected_file = try!(fs::File::create(&expected)); + try!(expected_file.write_all(output.as_bytes())); + } + + Err(Error::new(ErrorKind::Other, "Header and binding differ!")) +} + +fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { + let source = try!(fs::File::open(header)); + let reader = BufReader::new(source); + + // Scoop up bindgen-flags from test header + let mut flags = Vec::with_capacity(2); + + for line in reader.lines().take(3) { + let line = try!(line); + if line.contains("bindgen-flags: ") { + let extra_flags = line.split("bindgen-flags: ") + .last() + .and_then(shlex::split) + .unwrap(); + flags.extend(extra_flags.into_iter()); + } else if line.contains("bindgen-unstable") && + cfg!(feature = "testing_only_llvm_stable") { + return Ok(None); + } else if line.contains("bindgen-osx-only") { + let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; + flags = prepend_flags + .into_iter() + .map(ToString::to_string) + .chain(flags) + .collect(); + } + } + + // Fool builder_from_flags() into believing it has real env::args_os... + // - add "bindgen" as executable name 0th element + // - add header filename as 1st element + // - prepend raw lines so they're in the right order for expected output + // - append the test header's bindgen flags + let header_str = try!(header + .to_str() + .ok_or(Error::new(ErrorKind::Other, + "Invalid header file name"))); + + let prepend = ["bindgen", + "--with-derive-default", + header_str, + "--raw-line", + "", + "--raw-line", + "#![allow(non_snake_case)]", + "--raw-line", + ""]; + + let args = prepend + .into_iter() + .map(ToString::to_string) + .chain(flags.into_iter()); + + builder_from_flags(args).map(|(builder, _, _)| { + Some(builder.no_unstable_rust()) + }) +} + +macro_rules! test_header { + ($function:ident, $header:expr) => ( + #[test] + fn $function() { + let header = PathBuf::from($header); + let result = create_bindgen_builder(&header) + .and_then(|builder| { + if let Some(builder) = builder { + compare_generated_header(&header, builder) + } else { + Ok(()) + } + }); + + if let Err(err) = result { + panic!("{}", err); + } + } + ) +} + +// This file is generated by build.rs +include!(concat!(env!("OUT_DIR"), "/tests.rs")); + +#[test] +fn test_header_contents() { + let bindings = builder() + .header_contents("test.h", "int foo(const char* a);") + .no_unstable_rust() + .generate() + .unwrap() + .to_string(); + assert_eq!(bindings, + "/* automatically generated by rust-bindgen */ + +extern \"C\" { + pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +"); +} From 8f688c663c30486e53d9b5c62452b78628539113 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 14 Apr 2017 14:37:09 -0700 Subject: [PATCH 13/18] Fix the command line flags dumper for clang args ...and trailing whitespace. --- src/lib.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 993cd1c0c0..1e762f72ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,11 +235,11 @@ impl Builder { if !self.options.whitelist_recursively { output_vector.push("--no-recursive-whitelist".into()); } - + if self.options.objc_extern_crate { output_vector.push("--objc-extern-crate".into()); } - + if self.options.builtins { output_vector.push("--builtins".into()); } @@ -249,15 +249,6 @@ impl Builder { output_vector.push(prefix.clone()); } - self.options - .clang_args - .iter() - .map(|item| { - output_vector.push("--clang-args".into()); - output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); - }) - .count(); - if let Some(ref dummy) = self.options.dummy_uses { output_vector.push("--dummy-uses".into()); output_vector.push(dummy.clone()); @@ -316,7 +307,7 @@ impl Builder { if self.options.codegen_config.destructors { options.push("destructors".into()); } - + output_vector.push(options.join(",")); if !self.options.codegen_config.methods { @@ -410,6 +401,18 @@ impl Builder { }) .count(); + if !self.options.clang_args.is_empty() { + output_vector.push("--".into()); + self.options + .clang_args + .iter() + .cloned() + .map(|item| { + output_vector.push(item); + }) + .count(); + } + output_vector } @@ -1243,7 +1246,7 @@ fn commandline_flag_unit_test_function() { assert!(test_cases.iter().all(|ref x| command_line_flags.contains(x)) ); - //Test 2 + //Test 2 let bindings = ::builder().header("input_header") .whitelisted_type("Distinct_Type") .whitelisted_function("safe_function"); From 09475ea2efbbac6ff676b2ae0c27fb6a86bcc367 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 14 Apr 2017 15:51:54 -0700 Subject: [PATCH 14/18] Ensure that every item we `constrain` has a set of used template parameters This is a follow up to c8a206a, and the support for blacklisting in the named template parameter usage analysis. This ensures that ever item we ever call `constrain` on has an entry in `used` for the set of template parameters it uses. Additionally, it adds extra assertions to enforce the invariant. We cannot completely avoid analyzing blacklisted items because we want to consider all of a blacklisted template's parameters as used. This is why we ensure that blacklisted items have a used template parameter set rather than ensuring that blacklisted items never end up in the worklist. --- src/ir/named.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ir/named.rs b/src/ir/named.rs index 1af98a26ba..2bab5e4e9e 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -322,12 +322,14 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { for item in whitelisted_items.iter().cloned() { dependencies.entry(item).or_insert(vec![]); - used.insert(item, Some(ItemSet::new())); + used.entry(item).or_insert(Some(ItemSet::new())); { // We reverse our natural IR graph edges to find dependencies // between nodes. item.trace(ctx, &mut |sub_item, _| { + used.entry(sub_item).or_insert(Some(ItemSet::new())); + // We won't be generating code for items that aren't // whitelisted, so don't bother keeping track of their // template parameters. But isn't whitelisting the @@ -353,12 +355,17 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { &TypeKind::TemplateInstantiation(ref inst) => { let decl = ctx.resolve_type(inst.template_definition()); let args = inst.template_arguments(); + // Although template definitions should always have // template parameters, there is a single exception: // opaque templates. Hence the unwrap_or. let params = decl.self_template_params(ctx) .unwrap_or(vec![]); + for (arg, param) in args.iter().zip(params.iter()) { + used.entry(*arg).or_insert(Some(ItemSet::new())); + used.entry(*param).or_insert(Some(ItemSet::new())); + dependencies.entry(*arg) .or_insert(vec![]) .push(*param); @@ -368,6 +375,28 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { }); } + if cfg!(feature = "testing_only_extra_assertions") { + // Invariant: The `used` map has an entry for every whitelisted + // item, as well as all explicitly blacklisted items that are + // reachable from whitelisted items. + // + // (This is so that every item we call `constrain` on is guaranteed + // to have a set of template parameters, and we can allow + // blacklisted templates to use all of their parameters). + for item in whitelisted_items.iter() { + extra_assert!(used.contains_key(item)); + item.trace(ctx, &mut |sub_item, _| { + extra_assert!(used.contains_key(&sub_item)); + }, &()) + } + + // Invariant: the `dependencies` map has an entry for every + // whitelisted item. + for item in whitelisted_items.iter() { + extra_assert!(dependencies.contains_key(item)); + } + } + UsedTemplateParameters { ctx: ctx, used: used, From 848026da52225931cd53c63d7172988587f9fd00 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 16:34:50 -0400 Subject: [PATCH 15/18] Updated new test expectations --- build.rs | 31 +- src/codegen/mod.rs | 6662 ++++++++--------- src/ir/mod.rs | 23 + src/ir/module.rs | 91 + src/ir/objc.rs | 254 + src/ir/traversal.rs | 476 ++ src/ir/var.rs | 342 + src/main.rs | 22 +- src/options.rs | 2 +- .../tests/anonymous-template-types.rs | 70 +- tests/expectations/tests/class_nested.rs | 264 +- tests/expectations/tests/class_with_dtor.rs | 94 +- tests/expectations/tests/const_tparam.rs | 32 +- .../tests/default-template-parameter.rs | 62 +- .../tests/forward-declaration-autoptr.rs | 82 +- .../forward-inherit-struct-with-fields.rs | 50 +- tests/expectations/tests/inherit_named.rs | 40 +- ...issue-584-stylo-template-analysis-panic.rs | 161 +- tests/expectations/tests/namespace.rs | 206 +- tests/expectations/tests/nsStyleAutoArray.rs | 60 +- .../tests/replace_template_alias.rs | 38 +- tests/expectations/tests/replaces_double.rs | 38 +- .../tests/template-param-usage-0.rs | 30 +- .../tests/template-param-usage-10.rs | 58 +- .../tests/template-param-usage-12.rs | 50 +- .../tests/template-param-usage-13.rs | 42 +- .../tests/template-param-usage-15.rs | 48 +- .../tests/template-param-usage-2.rs | 48 +- .../tests/template-param-usage-3.rs | 54 +- .../tests/template-param-usage-4.rs | 40 +- .../tests/template-param-usage-5.rs | 32 +- .../tests/template-param-usage-7.rs | 36 +- .../tests/template-param-usage-8.rs | 38 +- .../tests/template-param-usage-9.rs | 48 +- tests/expectations/tests/template.rs | 558 +- tests/expectations/tests/template_alias.rs | 32 +- .../tests/template_alias_namespace.rs | 58 +- .../template_typedef_transitive_param.rs | 42 +- ..._alias_partial_template_especialization.rs | 32 +- tests/expectations/tests/using.rs | 36 +- tests/expectations/tests/what_is_going_on.rs | 66 +- tests/expectations/tests/whitelist_basic.rs | 50 +- tests/stylo_sanity.rs | 1096 +-- tests/tests.rs | 342 +- 44 files changed, 6561 insertions(+), 5375 deletions(-) create mode 100644 src/ir/mod.rs create mode 100644 src/ir/module.rs create mode 100644 src/ir/objc.rs create mode 100644 src/ir/traversal.rs create mode 100644 src/ir/var.rs diff --git a/build.rs b/build.rs index e299a671e3..bda91e28ac 100644 --- a/build.rs +++ b/build.rs @@ -26,34 +26,31 @@ mod testgen { pub fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut dst = File::create(Path::new(&out_dir).join("tests.rs")) - .unwrap(); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); - println!("cargo:rerun-if-changed=tests/headers"); - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR") - .unwrap()); + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let headers_dir = manifest_dir.join("tests").join("headers"); + let headers = match fs::read_dir(headers_dir) { + Ok(dir) => dir, + // We may not have headers directory after packaging. + Err(..) => return, + }; + let entries = - fs::read_dir(headers_dir) - .expect("Couldn't read headers dir") - .map(|result| result.expect("Couldn't read header file")); + headers.map(|result| result.expect("Couldn't read header file")); + + println!("cargo:rerun-if-changed=tests/headers"); for entry in entries { match entry.path().extension().and_then(OsStr::to_str) { Some("h") | Some("hpp") => { - let func = entry - .file_name() - .to_str() - .unwrap() + let func = entry.file_name().to_str().unwrap() .replace(|c| !char::is_alphanumeric(c), "_") .replace("__", "_") .to_lowercase(); - writeln!(dst, - "test_header!(header_{}, {:?});", - func, - entry.path()) - .unwrap(); + writeln!(dst, "test_header!(header_{}, {:?});", + func, entry.path()).unwrap(); } _ => {} } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 374a600ca3..8c860528fd 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,3331 +1,3331 @@ -mod error; -mod helpers; -mod struct_layout; - -use self::helpers::{BlobTyBuilder, attributes}; -use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; -use self::struct_layout::{align_to, bytes_from_bits}; -use aster; - -use ir::annotations::FieldAccessorKind; -use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; -use ir::context::{BindgenContext, ItemId}; -use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use ir::dot; -use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; -use ir::function::{Function, FunctionSig}; -use ir::int::IntKind; -use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath, - ItemSet}; -use ir::item_kind::ItemKind; -use ir::layout::Layout; -use ir::module::Module; -use ir::objc::{ObjCInterface, ObjCMethod}; -use ir::template::{AsNamed, TemplateInstantiation}; -use ir::ty::{TemplateDeclaration, Type, TypeKind}; -use ir::var::Var; - -use std::borrow::Cow; -use std::cell::Cell; -use std::cmp; -use std::collections::{HashSet, VecDeque}; -use std::collections::hash_map::{Entry, HashMap}; -use std::fmt::Write; -use std::mem; -use std::ops; -use syntax::abi::Abi; -use syntax::ast; -use syntax::codemap::{Span, respan}; -use syntax::ptr::P; - -fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { - if !ctx.options().enable_cxx_namespaces { - return 0; - } - - item.ancestors(ctx) - .filter(|id| ctx.resolve_item(*id).is_module()) - .fold(1, |i, _| i + 1) -} - -fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec { - let mut path = vec![ctx.rust_ident_raw("self")]; - - if ctx.options().enable_cxx_namespaces { - let super_ = ctx.rust_ident_raw("super"); - - for _ in 0..root_import_depth(ctx, item) { - path.push(super_.clone()); - } - } - - path -} - -fn root_import(ctx: &BindgenContext, module: &Item) -> P { - assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); - assert!(module.is_module()); - - let mut path = top_level_path(ctx, module); - - let root = ctx.root_module().canonical_name(ctx); - let root_ident = ctx.rust_ident(&root); - path.push(root_ident); - - let use_root = aster::AstBuilder::new() - .item() - .use_() - .ids(path) - .build() - .build(); - - quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() -} - -struct CodegenResult<'a> { - items: Vec>, - - /// A monotonic counter used to add stable unique id's to stuff that doesn't - /// need to be referenced by anything. - codegen_id: &'a Cell, - - /// Whether an union has been generated at least once. - saw_union: bool, - - /// Whether an incomplete array has been generated at least once. - saw_incomplete_array: bool, - - /// Whether Objective C types have been seen at least once. - saw_objc: bool, - - items_seen: HashSet, - /// The set of generated function/var names, needed because in C/C++ is - /// legal to do something like: - /// - /// ```c++ - /// extern "C" { - /// void foo(); - /// extern int bar; - /// } - /// - /// extern "C" { - /// void foo(); - /// extern int bar; - /// } - /// ``` - /// - /// Being these two different declarations. - functions_seen: HashSet, - vars_seen: HashSet, - - /// Used for making bindings to overloaded functions. Maps from a canonical - /// function name to the number of overloads we have already codegen'd for - /// that name. This lets us give each overload a unique suffix. - overload_counters: HashMap, -} - -impl<'a> CodegenResult<'a> { - fn new(codegen_id: &'a Cell) -> Self { - CodegenResult { - items: vec![], - saw_union: false, - saw_incomplete_array: false, - saw_objc: false, - codegen_id: codegen_id, - items_seen: Default::default(), - functions_seen: Default::default(), - vars_seen: Default::default(), - overload_counters: Default::default(), - } - } - - fn saw_union(&mut self) { - self.saw_union = true; - } - - fn saw_incomplete_array(&mut self) { - self.saw_incomplete_array = true; - } - - fn saw_objc(&mut self) { - self.saw_objc = true; - } - - fn seen(&self, item: ItemId) -> bool { - self.items_seen.contains(&item) - } - - fn set_seen(&mut self, item: ItemId) { - self.items_seen.insert(item); - } - - fn seen_function(&self, name: &str) -> bool { - self.functions_seen.contains(name) - } - - fn saw_function(&mut self, name: &str) { - self.functions_seen.insert(name.into()); - } - - /// Get the overload number for the given function name. Increments the - /// counter internally so the next time we ask for the overload for this - /// name, we get the incremented value, and so on. - fn overload_number(&mut self, name: &str) -> u32 { - let mut counter = - self.overload_counters.entry(name.into()).or_insert(0); - let number = *counter; - *counter += 1; - number - } - - fn seen_var(&self, name: &str) -> bool { - self.vars_seen.contains(name) - } - - fn saw_var(&mut self, name: &str) { - self.vars_seen.insert(name.into()); - } - - fn inner(&mut self, cb: F) -> Vec> - where F: FnOnce(&mut Self), - { - let mut new = Self::new(self.codegen_id); - - cb(&mut new); - - self.saw_union |= new.saw_union; - self.saw_incomplete_array |= new.saw_incomplete_array; - self.saw_objc |= new.saw_objc; - - new.items - } -} - -impl<'a> ops::Deref for CodegenResult<'a> { - type Target = Vec>; - - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl<'a> ops::DerefMut for CodegenResult<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.items - } -} - -struct ForeignModBuilder { - inner: ast::ForeignMod, -} - -impl ForeignModBuilder { - fn new(abi: Abi) -> Self { - ForeignModBuilder { - inner: ast::ForeignMod { - abi: abi, - items: vec![], - }, - } - } - - fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { - self.inner.items.push(item); - self - } - - #[allow(dead_code)] - fn with_foreign_items(mut self, items: I) -> Self - where I: IntoIterator, - { - self.inner.items.extend(items.into_iter()); - self - } - - fn build(self, ctx: &BindgenContext) -> P { - use syntax::codemap::DUMMY_SP; - P(ast::Item { - ident: ctx.rust_ident(""), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::ForeignMod(self.inner), - vis: ast::Visibility::Public, - attrs: vec![], - span: DUMMY_SP, - }) - } -} - -/// A trait to convert a rust type into a pointer, optionally const, to the same -/// type. -/// -/// This is done due to aster's lack of pointer builder, I guess I should PR -/// there. -trait ToPtr { - fn to_ptr(self, is_const: bool, span: Span) -> P; -} - -impl ToPtr for P { - fn to_ptr(self, is_const: bool, span: Span) -> Self { - let ty = ast::TyKind::Ptr(ast::MutTy { - ty: self, - mutbl: if is_const { - ast::Mutability::Immutable - } else { - ast::Mutability::Mutable - }, - }); - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: span, - }) - } -} - -trait CodeGenerator { - /// Extra information from the caller. - type Extra; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - extra: &Self::Extra); -} - -impl CodeGenerator for Item { - type Extra = (); - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - _extra: &()) { - if self.is_hidden(ctx) || result.seen(self.id()) { - debug!("::codegen: Ignoring hidden or seen: \ - self = {:?}", - self); - return; - } - - debug!("::codegen: self = {:?}", self); - if !whitelisted_items.contains(&self.id()) { - // TODO(emilio, #453): Figure out what to do when this happens - // legitimately, we could track the opaque stuff and disable the - // assertion there I guess. - error!("Found non-whitelisted item in code generation: {:?}", self); - } - - result.set_seen(self.id()); - - match *self.kind() { - ItemKind::Module(ref module) => { - module.codegen(ctx, result, whitelisted_items, self); - } - ItemKind::Function(ref fun) => { - if ctx.options().codegen_config.functions { - fun.codegen(ctx, result, whitelisted_items, self); - } - } - ItemKind::Var(ref var) => { - if ctx.options().codegen_config.vars { - var.codegen(ctx, result, whitelisted_items, self); - } - } - ItemKind::Type(ref ty) => { - if ctx.options().codegen_config.types { - ty.codegen(ctx, result, whitelisted_items, self); - } - } - } - } -} - -impl CodeGenerator for Module { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let codegen_self = |result: &mut CodegenResult, - found_any: &mut bool| { - for child in self.children() { - if whitelisted_items.contains(child) { - *found_any = true; - ctx.resolve_item(*child) - .codegen(ctx, result, whitelisted_items, &()); - } - } - - if item.id() == ctx.root_module() { - if result.saw_union && !ctx.options().unstable_rust { - utils::prepend_union_types(ctx, &mut *result); - } - if result.saw_incomplete_array { - utils::prepend_incomplete_array_types(ctx, &mut *result); - } - if ctx.need_bindegen_complex_type() { - utils::prepend_complex_type(ctx, &mut *result); - } - if result.saw_objc { - utils::prepend_objc_header(ctx, &mut *result); - } - } - }; - - if !ctx.options().enable_cxx_namespaces || - (self.is_inline() && !ctx.options().conservative_inline_namespaces) { - codegen_self(result, &mut false); - return; - } - - let mut found_any = false; - let inner_items = result.inner(|result| { - result.push(root_import(ctx, item)); - codegen_self(result, &mut found_any); - }); - - // Don't bother creating an empty module. - if !found_any { - return; - } - - let module = ast::ItemKind::Mod(ast::Mod { - inner: ctx.span(), - items: inner_items, - }); - - let name = item.canonical_name(ctx); - let item_builder = aster::AstBuilder::new() - .item() - .pub_(); - let item = if name == "root" { - let attrs = &["non_snake_case", - "non_camel_case_types", - "non_upper_case_globals"]; - item_builder.with_attr(attributes::allow(attrs)) - .build_item_kind(name, module) - } else { - item_builder.build_item_kind(name, module) - }; - - result.push(item); - } -} - -impl CodeGenerator for Var { - type Extra = Item; - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - use ir::var::VarType; - debug!("::codegen: item = {:?}", item); - - let canonical_name = item.canonical_name(ctx); - - if result.seen_var(&canonical_name) { - return; - } - result.saw_var(&canonical_name); - - let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); - - if let Some(val) = self.val() { - let const_item = aster::AstBuilder::new() - .item() - .pub_() - .const_(canonical_name) - .expr(); - let item = match *val { - VarType::Bool(val) => { - const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) - } - VarType::Int(val) => { - const_item.build(helpers::ast_ty::int_expr(val)).build(ty) - } - VarType::String(ref bytes) => { - // Account the trailing zero. - // - // TODO: Here we ignore the type we just made up, probably - // we should refactor how the variable type and ty id work. - let len = bytes.len() + 1; - let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); - - match String::from_utf8(bytes.clone()) { - Ok(string) => { - const_item.build(helpers::ast_ty::cstr_expr(string)) - .build(quote_ty!(ctx.ext_cx(), &'static $ty)) - } - Err(..) => { - const_item - .build(helpers::ast_ty::byte_array_expr(bytes)) - .build(ty) - } - } - } - VarType::Float(f) => { - match helpers::ast_ty::float_expr(ctx, f) { - Ok(expr) => { - const_item.build(expr).build(ty) - } - Err(..) => return, - } - } - VarType::Char(c) => { - const_item - .build(aster::AstBuilder::new().expr().lit().byte(c)) - .build(ty) - } - }; - - result.push(item); - } else { - let mut attrs = vec![]; - if let Some(mangled) = self.mangled_name() { - attrs.push(attributes::link_name(mangled)); - } else if canonical_name != self.name() { - attrs.push(attributes::link_name(self.name())); - } - - let item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attrs, - node: ast::ForeignItemKind::Static(ty, !self.is_const()), - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, - }; - - let item = ForeignModBuilder::new(Abi::C) - .with_foreign_item(item) - .build(ctx); - result.push(item); - } - } -} - -impl CodeGenerator for Type { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - match *self.kind() { - TypeKind::Void | - TypeKind::NullPtr | - TypeKind::Int(..) | - TypeKind::Float(..) | - TypeKind::Complex(..) | - TypeKind::Array(..) | - TypeKind::Pointer(..) | - TypeKind::BlockPointer | - TypeKind::Reference(..) | - TypeKind::Function(..) | - TypeKind::ResolvedTypeRef(..) | - TypeKind::Opaque | - TypeKind::Named => { - // These items don't need code generation, they only need to be - // converted to rust types in fields, arguments, and such. - return; - } - TypeKind::TemplateInstantiation(ref inst) => { - inst.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::Comp(ref ci) => { - ci.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::TemplateAlias(inner, _) | - TypeKind::Alias(inner) => { - let inner_item = ctx.resolve_item(inner); - let name = item.canonical_name(ctx); - - // Try to catch the common pattern: - // - // typedef struct foo { ... } foo; - // - // here. - // - if inner_item.canonical_name(ctx) == name { - return; - } - - // If this is a known named type, disallow generating anything - // for it too. - let spelling = self.name().expect("Unnamed alias?"); - if utils::type_from_named(ctx, spelling, inner).is_some() { - return; - } - - let mut used_template_params = item.used_template_params(ctx); - let inner_rust_type = if item.is_opaque(ctx) { - used_template_params = None; - self.to_opaque(ctx, item) - } else { - // Its possible that we have better layout information than - // the inner type does, so fall back to an opaque blob based - // on our layout if converting the inner item fails. - inner_item.try_to_rust_ty_or_opaque(ctx, &()) - .unwrap_or_else(|_| self.to_opaque(ctx, item)) - }; - - { - // FIXME(emilio): This is a workaround to avoid generating - // incorrect type aliases because of types that we haven't - // been able to resolve (because, eg, they depend on a - // template parameter). - // - // It's kind of a shame not generating them even when they - // could be referenced, but we already do the same for items - // with invalid template parameters, and at least this way - // they can be replaced, instead of generating plain invalid - // code. - let inner_canon_type = inner_item.expect_type() - .canonical_type(ctx); - if inner_canon_type.is_invalid_named_type() { - warn!("Item contained invalid named type, skipping: \ - {:?}, {:?}", - item, - inner_item); - return; - } - } - - let rust_name = ctx.rust_ident(&name); - let mut typedef = aster::AstBuilder::new().item().pub_(); - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - typedef = typedef.attr().doc(comment); - } - } - - // We prefer using `pub use` over `pub type` because of: - // https://github.com/rust-lang/rust/issues/26264 - let simple_enum_path = match inner_rust_type.node { - ast::TyKind::Path(None, ref p) => { - if used_template_params.is_none() && - inner_item.expect_type() - .canonical_type(ctx) - .is_enum() && - p.segments.iter().all(|p| p.parameters.is_none()) { - Some(p.clone()) - } else { - None - } - } - _ => None, - }; - - let typedef = if let Some(mut p) = simple_enum_path { - for ident in top_level_path(ctx, item).into_iter().rev() { - p.segments.insert(0, - ast::PathSegment { - identifier: ident, - parameters: None, - }); - } - typedef.use_().build(p).as_(rust_name) - } else { - let mut generics = typedef.type_(rust_name).generics(); - if let Some(ref params) = used_template_params { - for template_param in params { - if let Some(id) = - template_param.as_named(ctx, &()) { - let template_param = ctx.resolve_type(id); - if template_param.is_invalid_named_type() { - warn!("Item contained invalid template \ - parameter: {:?}", - item); - return; - } - generics = - generics.ty_param_id(template_param.name() - .unwrap()); - } - } - } - generics.build().build_ty(inner_rust_type) - }; - result.push(typedef) - } - TypeKind::Enum(ref ei) => { - ei.codegen(ctx, result, whitelisted_items, item) - } - TypeKind::ObjCId | TypeKind::ObjCSel => { - result.saw_objc(); - } - TypeKind::ObjCInterface(ref interface) => { - interface.codegen(ctx, result, whitelisted_items, item) - } - ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) - } - } - } -} - -struct Vtable<'a> { - item_id: ItemId, - #[allow(dead_code)] - methods: &'a [Method], - #[allow(dead_code)] - base_classes: &'a [Base], -} - -impl<'a> Vtable<'a> { - fn new(item_id: ItemId, - methods: &'a [Method], - base_classes: &'a [Base]) - -> Self { - Vtable { - item_id: item_id, - methods: methods, - base_classes: base_classes, - } - } -} - -impl<'a> CodeGenerator for Vtable<'a> { - type Extra = Item; - - fn codegen<'b>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'b>, - _whitelisted_items: &ItemSet, - item: &Item) { - assert_eq!(item.id(), self.item_id); - // For now, generate an empty struct, later we should generate function - // pointers and whatnot. - let attributes = vec![attributes::repr("C")]; - - let vtable = aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .tuple_struct(self.canonical_name(ctx)) - .field() - .build_ty(helpers::ast_ty::raw_type(ctx, "c_void")) - .build(); - result.push(vtable); - } -} - -impl<'a> ItemCanonicalName for Vtable<'a> { - fn canonical_name(&self, ctx: &BindgenContext) -> String { - format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) - } -} - -impl<'a> TryToRustTy for Vtable<'a> { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) -> error::Result> { - Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) - } -} - -struct Bitfield<'a> { - index: &'a mut usize, - fields: Vec<&'a Field>, -} - -impl<'a> Bitfield<'a> { - fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self { - Bitfield { - index: index, - fields: fields, - } - } - - fn codegen_fields(self, - ctx: &BindgenContext, - parent: &CompInfo, - fields: &mut Vec, - methods: &mut Vec) - -> Layout { - // NOTE: What follows is reverse-engineered from LLVM's - // lib/AST/RecordLayoutBuilder.cpp - // - // FIXME(emilio): There are some differences between Microsoft and the - // Itanium ABI, but we'll ignore those and stick to Itanium for now. - // - // Also, we need to handle packed bitfields and stuff. - // TODO(emilio): Take into account C++'s wide bitfields, and - // packing, sigh. - let mut total_size_in_bits = 0; - let mut max_align = 0; - let mut unfilled_bits_in_last_unit = 0; - let mut field_size_in_bits = 0; - *self.index += 1; - let mut last_field_name = format!("_bitfield_{}", self.index); - let mut last_field_align = 0; - - // (name, mask, width, bitfield's type, bitfield's layout) - let mut bitfields: Vec<(&str, usize, usize, ast::Ty, Layout)> = vec![]; - - for field in self.fields { - let width = field.bitfield().unwrap() as usize; - let field_item = ctx.resolve_item(field.ty()); - let field_ty_layout = field_item.kind() - .expect_type() - .layout(ctx) - .expect("Bitfield without layout? Gah!"); - let field_align = field_ty_layout.align; - - if field_size_in_bits != 0 && - (width == 0 || width > unfilled_bits_in_last_unit) { - // We've finished a physical field, so flush it and its bitfields. - field_size_in_bits = align_to(field_size_in_bits, field_align); - fields.push(flush_bitfields(ctx, - parent, - field_size_in_bits, - last_field_align, - &last_field_name, - bitfields.drain(..), - methods)); - - // TODO(emilio): dedup this. - *self.index += 1; - last_field_name = format!("_bitfield_{}", self.index); - - // Now reset the size and the rest of stuff. - // unfilled_bits_in_last_unit = 0; - field_size_in_bits = 0; - last_field_align = 0; - } - - if let Some(name) = field.name() { - let field_item_ty = field_item.to_rust_ty_or_opaque(ctx, &()); - bitfields.push((name, - field_size_in_bits, - width, - field_item_ty.unwrap(), - field_ty_layout)); - } - - field_size_in_bits += width; - total_size_in_bits += width; - - let data_size = align_to(field_size_in_bits, field_align * 8); - - max_align = cmp::max(max_align, field_align); - - // NB: The width here is completely, absolutely intentional. - last_field_align = cmp::max(last_field_align, width); - - unfilled_bits_in_last_unit = data_size - field_size_in_bits; - } - - if field_size_in_bits != 0 { - // Flush the last physical field and its bitfields. - fields.push(flush_bitfields(ctx, - parent, - field_size_in_bits, - last_field_align, - &last_field_name, - bitfields.drain(..), - methods)); - } - - Layout::new(bytes_from_bits(total_size_in_bits), max_align) - } -} - -fn parent_has_method(ctx: &BindgenContext, - parent: &CompInfo, - name: &str) - -> bool { - parent.methods().iter().any(|method| { - let method_name = match *ctx.resolve_item(method.signature()).kind() { - ItemKind::Function(ref func) => func.name(), - ref otherwise => panic!("a method's signature should always be a \ - item of kind ItemKind::Function, found: \ - {:?}", - otherwise), - }; - - method_name == name || ctx.rust_mangle(&method_name) == name - }) -} - -fn bitfield_getter_name(ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str) - -> ast::Ident { - let name = ctx.rust_mangle(bitfield_name); - - if parent_has_method(ctx, parent, &name) { - let mut name = name.to_string(); - name.push_str("_bindgen_bitfield"); - return ctx.ext_cx().ident_of(&name); - } - - ctx.ext_cx().ident_of(&name) -} - -fn bitfield_setter_name(ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str) - -> ast::Ident { - let setter = format!("set_{}", bitfield_name); - let mut setter = ctx.rust_mangle(&setter).to_string(); - - if parent_has_method(ctx, parent, &setter) { - setter.push_str("_bindgen_bitfield"); - } - - ctx.ext_cx().ident_of(&setter) -} - -/// A physical field (which is a word or byte or ...) has many logical bitfields -/// contained within it, but not all bitfields are in the same physical field of -/// a struct. This function creates a single physical field and flushes all the -/// accessors for the logical `bitfields` within that physical field to the -/// outgoing `methods`. -fn flush_bitfields<'a, I>(ctx: &BindgenContext, - parent: &CompInfo, - field_size_in_bits: usize, - field_align: usize, - field_name: &str, - bitfields: I, - methods: &mut Vec) -> ast::StructField - where I: IntoIterator -{ - use aster::struct_field::StructFieldBuilder; - - let field_layout = Layout::new(bytes_from_bits_pow2(field_size_in_bits), - bytes_from_bits_pow2(field_align)); - let field_ty = BlobTyBuilder::new(field_layout).build(); - - let field = StructFieldBuilder::named(field_name) - .pub_() - .build_ty(field_ty.clone()); - - let field_int_ty = match field_layout.size { - 8 => quote_ty!(ctx.ext_cx(), u64), - 4 => quote_ty!(ctx.ext_cx(), u32), - 2 => quote_ty!(ctx.ext_cx(), u16), - 1 => quote_ty!(ctx.ext_cx(), u8), - _ => return field - }; - - for (name, offset, width, bitfield_ty, bitfield_layout) in bitfields { - let prefix = ctx.trait_prefix(); - let getter_name = bitfield_getter_name(ctx, parent, name); - let setter_name = bitfield_setter_name(ctx, parent, name); - let field_ident = ctx.ext_cx().ident_of(field_name); - - let bitfield_int_ty = BlobTyBuilder::new(bitfield_layout).build(); - - let mask: usize = ((1usize << width) - 1usize) << offset; - - let impl_item = quote_item!( - ctx.ext_cx(), - impl XxxIgnored { - #[inline] - pub fn $getter_name(&self) -> $bitfield_ty { - let mask = $mask as $field_int_ty; - let field_val: $field_int_ty = unsafe { - ::$prefix::mem::transmute(self.$field_ident) - }; - let val = (field_val & mask) >> $offset; - unsafe { - ::$prefix::mem::transmute(val as $bitfield_int_ty) - } - } - - #[inline] - pub fn $setter_name(&mut self, val: $bitfield_ty) { - let mask = $mask as $field_int_ty; - let val = val as $bitfield_int_ty as $field_int_ty; - - let mut field_val: $field_int_ty = unsafe { - ::$prefix::mem::transmute(self.$field_ident) - }; - field_val &= !mask; - field_val |= (val << $offset) & mask; - - self.$field_ident = unsafe { - ::$prefix::mem::transmute(field_val) - }; - } - } - ).unwrap(); - - match impl_item.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, items) => { - methods.extend(items.into_iter()); - }, - _ => unreachable!(), - }; - } - - field -} - -impl CodeGenerator for TemplateInstantiation { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - // Although uses of instantiations don't need code generation, and are - // just converted to rust types in fields, vars, etc, we take this - // opportunity to generate tests for their layout here. - if !ctx.options().layout_tests { - return - } - - let layout = item.kind().expect_type().layout(ctx); - - if let Some(layout) = layout { - let size = layout.size; - let align = layout.align; - - let name = item.canonical_name(ctx); - let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", - name, - item.id().as_usize()); - let fn_name = ctx.rust_ident_raw(&fn_name); - - let prefix = ctx.trait_prefix(); - let ident = item.to_rust_ty_or_opaque(ctx, &()); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$ident>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$ident>()); - - let item = quote_item!( - ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size, - concat!("Size of template specialization: ", stringify!($ident))); - assert_eq!($align_of_expr, $align, - concat!("Alignment of template specialization: ", stringify!($ident))); - }) - .unwrap(); - - result.push(item); - } - } -} - -impl CodeGenerator for CompInfo { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - item: &Item) { - use aster::struct_field::StructFieldBuilder; - - debug!("::codegen: item = {:?}", item); - - // Don't output classes with template parameters that aren't types, and - // also don't output template specializations, neither total or partial. - if self.has_non_type_template_params() { - return; - } - - let used_template_params = item.used_template_params(ctx); - - // generate tuple struct if struct or union is a forward declaration, - // skip for now if template parameters are needed. - if self.is_forward_declaration() && used_template_params.is_none() { - let struct_name = item.canonical_name(ctx); - let struct_name = ctx.rust_ident_raw(&struct_name); - let tuple_struct = quote_item!(ctx.ext_cx(), - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct $struct_name([u8; 0]); - ) - .unwrap(); - result.push(tuple_struct); - return; - } - - let mut attributes = vec![]; - let mut needs_clone_impl = false; - let mut needs_default_impl = false; - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - attributes.push(attributes::doc(comment)); - } - } - if self.packed() { - attributes.push(attributes::repr_list(&["C", "packed"])); - } else { - attributes.push(attributes::repr("C")); - } - - let is_union = self.kind() == CompKind::Union; - let mut derives = vec![]; - if item.can_derive_debug(ctx, ()) { - derives.push("Debug"); - } - - if item.can_derive_default(ctx, ()) { - derives.push("Default"); - } else { - needs_default_impl = ctx.options().derive_default; - } - - if item.can_derive_copy(ctx, ()) && - !item.annotations().disallow_copy() { - derives.push("Copy"); - if used_template_params.is_some() { - // FIXME: This requires extra logic if you have a big array in a - // templated struct. The reason for this is that the magic: - // fn clone(&self) -> Self { *self } - // doesn't work for templates. - // - // It's not hard to fix though. - derives.push("Clone"); - } else { - needs_clone_impl = true; - } - } - - if !derives.is_empty() { - attributes.push(attributes::derives(&derives)) - } - - let canonical_name = item.canonical_name(ctx); - let builder = if is_union && ctx.options().unstable_rust { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .union_(&canonical_name) - } else { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .struct_(&canonical_name) - }; - - // Generate the vtable from the method list if appropriate. - // - // TODO: I don't know how this could play with virtual methods that are - // not in the list of methods found by us, we'll see. Also, could the - // order of the vtable pointers vary? - // - // FIXME: Once we generate proper vtables, we need to codegen the - // vtable, but *not* generate a field for it in the case that - // needs_explicit_vtable is false but has_vtable is true. - // - // Also, we need to generate the vtable in such a way it "inherits" from - // the parent too. - let mut fields = vec![]; - let mut struct_layout = StructLayoutTracker::new(ctx, self); - if self.needs_explicit_vtable(ctx) { - let vtable = - Vtable::new(item.id(), self.methods(), self.base_members()); - vtable.codegen(ctx, result, whitelisted_items, item); - - let vtable_type = vtable.try_to_rust_ty(ctx, &()) - .expect("vtable to Rust type conversion is infallible") - .to_ptr(true, ctx.span()); - - let vtable_field = StructFieldBuilder::named("vtable_") - .pub_() - .build_ty(vtable_type); - - struct_layout.saw_vtable(); - - fields.push(vtable_field); - } - - for (i, base) in self.base_members().iter().enumerate() { - // Virtual bases are already taken into account by the vtable - // pointer. - // - // FIXME(emilio): Is this always right? - if base.is_virtual() { - continue; - } - - let base_ty = ctx.resolve_type(base.ty); - // NB: We won't include unsized types in our base chain because they - // would contribute to our size given the dummy field we insert for - // unsized types. - if base_ty.is_unsized(ctx) { - continue; - } - - let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); - let field_name = if i == 0 { - "_base".into() - } else { - format!("_base_{}", i) - }; - - struct_layout.saw_base(base_ty); - - let field = StructFieldBuilder::named(field_name) - .pub_() - .build_ty(inner); - fields.push(field); - } - if is_union { - result.saw_union(); - } - - let layout = item.kind().expect_type().layout(ctx); - - let mut current_bitfield_width = None; - let mut current_bitfield_layout: Option = None; - let mut current_bitfield_fields = vec![]; - let mut bitfield_count = 0; - let struct_fields = self.fields(); - let fields_should_be_private = item.annotations() - .private_fields() - .unwrap_or(false); - let struct_accessor_kind = item.annotations() - .accessor_kind() - .unwrap_or(FieldAccessorKind::None); - - let mut methods = vec![]; - let mut anonymous_field_count = 0; - for field in struct_fields { - debug_assert_eq!(current_bitfield_width.is_some(), - current_bitfield_layout.is_some()); - debug_assert_eq!(current_bitfield_width.is_some(), - !current_bitfield_fields.is_empty()); - - let field_ty = ctx.resolve_type(field.ty()); - - // Try to catch a bitfield contination early. - if let (Some(ref mut bitfield_width), Some(width)) = - (current_bitfield_width, field.bitfield()) { - let layout = current_bitfield_layout.unwrap(); - debug!("Testing bitfield continuation {} {} {:?}", - *bitfield_width, - width, - layout); - if *bitfield_width + width <= (layout.size * 8) as u32 { - *bitfield_width += width; - current_bitfield_fields.push(field); - continue; - } - } - - // Flush the current bitfield. - if current_bitfield_width.is_some() { - debug_assert!(!current_bitfield_fields.is_empty()); - let bitfield_fields = - mem::replace(&mut current_bitfield_fields, vec![]); - let bitfield_layout = Bitfield::new(&mut bitfield_count, - bitfield_fields) - .codegen_fields(ctx, self, &mut fields, &mut methods); - struct_layout.saw_bitfield_batch(bitfield_layout); - - current_bitfield_width = None; - current_bitfield_layout = None; - } - debug_assert!(current_bitfield_fields.is_empty()); - - if let Some(width) = field.bitfield() { - let layout = field_ty.layout(ctx) - .expect("Bitfield type without layout?"); - current_bitfield_width = Some(width); - current_bitfield_layout = Some(layout); - current_bitfield_fields.push(field); - continue; - } - - let ty = field.ty().to_rust_ty_or_opaque(ctx, &()); - - // NB: In unstable rust we use proper `union` types. - let ty = if is_union && !ctx.options().unstable_rust { - if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) - } else { - quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) - } - } else if let Some(item) = - field_ty.is_incomplete_array(ctx) { - result.saw_incomplete_array(); - - let inner = item.to_rust_ty_or_opaque(ctx, &()); - - if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) - } else { - quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) - } - } else { - ty - }; - - let mut attrs = vec![]; - if ctx.options().generate_comments { - if let Some(comment) = field.comment() { - attrs.push(attributes::doc(comment)); - } - } - let field_name = match field.name() { - Some(name) => ctx.rust_mangle(name).into_owned(), - None => { - anonymous_field_count += 1; - format!("__bindgen_anon_{}", anonymous_field_count) - } - }; - - if !is_union { - if let Some(padding_field) = - struct_layout.pad_field(&field_name, field_ty, field.offset()) { - fields.push(padding_field); - } - } - - let is_private = field.annotations() - .private_fields() - .unwrap_or(fields_should_be_private); - - let accessor_kind = field.annotations() - .accessor_kind() - .unwrap_or(struct_accessor_kind); - - let mut field = StructFieldBuilder::named(&field_name); - - if !is_private { - field = field.pub_(); - } - - let field = field.with_attrs(attrs) - .build_ty(ty.clone()); - - fields.push(field); - - // TODO: Factor the following code out, please! - if accessor_kind == FieldAccessorKind::None { - continue; - } - - let getter_name = - ctx.rust_ident_raw(&format!("get_{}", field_name)); - let mutable_getter_name = - ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); - let field_name = ctx.rust_ident_raw(&field_name); - - let accessor_methods_impl = match accessor_kind { - FieldAccessorKind::None => unreachable!(), - FieldAccessorKind::Regular => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } - - #[inline] - pub fn $mutable_getter_name(&mut self) -> &mut $ty { - &mut self.$field_name - } - } - ) - } - FieldAccessorKind::Unsafe => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub unsafe fn $getter_name(&self) -> &$ty { - &self.$field_name - } - - #[inline] - pub unsafe fn $mutable_getter_name(&mut self) - -> &mut $ty { - &mut self.$field_name - } - } - ) - } - FieldAccessorKind::Immutable => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } - } - ) - } - }; - - match accessor_methods_impl.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => { - methods.extend(items.clone()) - } - _ => unreachable!(), - } - } - - // Flush the last bitfield if any. - // - // FIXME: Reduce duplication with the loop above. - // FIXME: May need to pass current_bitfield_layout too. - if current_bitfield_width.is_some() { - debug_assert!(!current_bitfield_fields.is_empty()); - let bitfield_fields = mem::replace(&mut current_bitfield_fields, - vec![]); - let bitfield_layout = Bitfield::new(&mut bitfield_count, - bitfield_fields) - .codegen_fields(ctx, self, &mut fields, &mut methods); - struct_layout.saw_bitfield_batch(bitfield_layout); - } - debug_assert!(current_bitfield_fields.is_empty()); - - if is_union && !ctx.options().unstable_rust { - let layout = layout.expect("Unable to get layout information?"); - let ty = BlobTyBuilder::new(layout).build(); - let field = StructFieldBuilder::named("bindgen_union_field") - .pub_() - .build_ty(ty); - - struct_layout.saw_union(layout); - - fields.push(field); - } - - // Yeah, sorry about that. - if item.is_opaque(ctx) { - fields.clear(); - methods.clear(); - - match layout { - Some(l) => { - let ty = BlobTyBuilder::new(l).build(); - let field = - StructFieldBuilder::named("_bindgen_opaque_blob") - .pub_() - .build_ty(ty); - fields.push(field); - } - None => { - warn!("Opaque type without layout! Expect dragons!"); - } - } - } else if !is_union && !self.is_unsized(ctx) { - if let Some(padding_field) = - layout.and_then(|layout| { - struct_layout.pad_struct(&canonical_name, layout) - }) { - fields.push(padding_field); - } - - if let Some(align_field) = - layout.and_then(|layout| struct_layout.align_struct(layout)) { - fields.push(align_field); - } - } - - // C++ requires every struct to be addressable, so what C++ compilers do - // is making the struct 1-byte sized. - // - // This is apparently not the case for C, see: - // https://github.com/servo/rust-bindgen/issues/551 - // - // Just get the layout, and assume C++ if not. - // - // NOTE: This check is conveniently here to avoid the dummy fields we - // may add for unused template parameters. - if self.is_unsized(ctx) { - let has_address = layout.map_or(true, |l| l.size != 0); - if has_address { - let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); - let field = StructFieldBuilder::named("_address") - .pub_() - .build_ty(ty); - fields.push(field); - } - } - - let mut generics = aster::AstBuilder::new().generics(); - - if let Some(ref params) = used_template_params { - for (idx, ty) in params.iter().enumerate() { - let param = ctx.resolve_type(*ty); - let name = param.name().unwrap(); - let ident = ctx.rust_ident(name); - - generics = generics.ty_param_id(ident); - - let prefix = ctx.trait_prefix(); - let phantom_ty = quote_ty!( - ctx.ext_cx(), - ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); - let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) - .build_ty(phantom_ty); - fields.push(phantom_field); - } - } - - let generics = generics.build(); - - let rust_struct = builder.with_generics(generics.clone()) - .with_fields(fields) - .build(); - result.push(rust_struct); - - // Generate the inner types and all that stuff. - // - // TODO: In the future we might want to be smart, and use nested - // modules, and whatnot. - for ty in self.inner_types() { - let child_item = ctx.resolve_item(*ty); - // assert_eq!(child_item.parent_id(), item.id()); - child_item.codegen(ctx, result, whitelisted_items, &()); - } - - // NOTE: Some unexposed attributes (like alignment attributes) may - // affect layout, so we're bad and pray to the gods for avoid sending - // all the tests to shit when parsing things like max_align_t. - if self.found_unknown_attr() { - warn!("Type {} has an unkown attribute that may affect layout", - canonical_name); - } - - if used_template_params.is_none() { - for var in self.inner_vars() { - ctx.resolve_item(*var) - .codegen(ctx, result, whitelisted_items, &()); - } - - if ctx.options().layout_tests { - if let Some(layout) = layout { - let fn_name = format!("bindgen_test_layout_{}", canonical_name); - let fn_name = ctx.rust_ident_raw(&fn_name); - let type_name = ctx.rust_ident_raw(&canonical_name); - let prefix = ctx.trait_prefix(); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$type_name>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$type_name>()); - let size = layout.size; - let align = layout.align; - - let check_struct_align = if align > mem::size_of::<*mut ()>() { - // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready - None - } else { - quote_item!(ctx.ext_cx(), - assert_eq!($align_of_expr, - $align, - concat!("Alignment of ", stringify!($type_name))); - ) - }; - - // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready - let too_many_base_vtables = self.base_members() - .iter() - .filter(|base| { - ctx.resolve_type(base.ty).has_vtable(ctx) - }) - .count() > 1; - - let should_skip_field_offset_checks = item.is_opaque(ctx) || - too_many_base_vtables; - - let check_field_offset = if should_skip_field_offset_checks { - None - } else { - let asserts = self.fields() - .iter() - .filter(|field| field.bitfield().is_none()) - .flat_map(|field| { - field.name().and_then(|name| { - field.offset().and_then(|offset| { - let field_offset = offset / 8; - let field_name = ctx.rust_ident(name); - - quote_item!(ctx.ext_cx(), - assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, - $field_offset, - concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); - ) - }) - }) - }).collect::>>(); - - Some(asserts) - }; - - let item = quote_item!(ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, - $size, - concat!("Size of: ", stringify!($type_name))); - - $check_struct_align - $check_field_offset - }) - .unwrap(); - result.push(item); - } - } - - let mut method_names = Default::default(); - if ctx.options().codegen_config.methods { - for method in self.methods() { - assert!(method.kind() != MethodKind::Constructor); - method.codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - - if ctx.options().codegen_config.constructors { - for sig in self.constructors() { - Method::new(MethodKind::Constructor, - *sig, - /* const */ - false) - .codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - - if ctx.options().codegen_config.destructors { - if let Some((is_virtual, destructor)) = self.destructor() { - let kind = if is_virtual { - MethodKind::VirtualDestructor - } else { - MethodKind::Destructor - }; - - Method::new(kind, destructor, false) - .codegen_method(ctx, - &mut methods, - &mut method_names, - result, - whitelisted_items, - self); - } - } - } - - // NB: We can't use to_rust_ty here since for opaque types this tries to - // use the specialization knowledge to generate a blob field. - let ty_for_impl = aster::AstBuilder::new() - .ty() - .path() - .segment(&canonical_name) - .with_generics(generics.clone()) - .build() - .build(); - - if needs_clone_impl { - let impl_ = quote_item!(ctx.ext_cx(), - impl X { - fn clone(&self) -> Self { *self } - } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let clone_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Clone") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(clone_impl); - } - - if needs_default_impl { - let prefix = ctx.trait_prefix(); - let impl_ = quote_item!(ctx.ext_cx(), - impl X { - fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } - } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let default_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Default") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(default_impl); - } - - if !methods.is_empty() { - let methods = aster::AstBuilder::new() - .item() - .impl_() - .with_generics(generics) - .with_items(methods) - .build_ty(ty_for_impl); - result.push(methods); - } - } -} - -trait MethodCodegen { - fn codegen_method<'a>(&self, - ctx: &BindgenContext, - methods: &mut Vec, - method_names: &mut HashMap, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - parent: &CompInfo); -} - -impl MethodCodegen for Method { - fn codegen_method<'a>(&self, - ctx: &BindgenContext, - methods: &mut Vec, - method_names: &mut HashMap, - result: &mut CodegenResult<'a>, - whitelisted_items: &ItemSet, - _parent: &CompInfo) { - if self.is_virtual() { - return; // FIXME - } - - // First of all, output the actual function. - let function_item = ctx.resolve_item(self.signature()); - function_item.codegen(ctx, result, whitelisted_items, &()); - - let function = function_item.expect_function(); - let signature_item = ctx.resolve_item(function.signature()); - let mut name = match self.kind() { - MethodKind::Constructor => "new".into(), - MethodKind::Destructor => "destruct".into(), - _ => function.name().to_owned(), - }; - - let signature = match *signature_item.expect_type().kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How in the world?"), - }; - - // Do not generate variadic methods, since rust does not allow - // implementing them, and we don't do a good job at it anyway. - if signature.is_variadic() { - return; - } - - let count = { - let mut count = method_names.entry(name.clone()) - .or_insert(0); - *count += 1; - *count - 1 - }; - - if count != 0 { - name.push_str(&count.to_string()); - } - - let function_name = function_item.canonical_name(ctx); - let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) - .unwrap(); - if !self.is_static() && !self.is_constructor() { - let mutability = if self.is_const() { - ast::Mutability::Immutable - } else { - ast::Mutability::Mutable - }; - - assert!(!fndecl.inputs.is_empty()); - - // FIXME: use aster here. - fndecl.inputs[0] = ast::Arg { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Rptr(None, ast::MutTy { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::ImplicitSelf, - span: ctx.span() - }), - mutbl: mutability, - }), - span: ctx.span(), - }), - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident( - ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span(), ctx.ext_cx().ident_of("self")), - None - ), - span: ctx.span(), - }), - id: ast::DUMMY_NODE_ID, - }; - } - - // If it's a constructor, we always return `Self`, and we inject the - // "this" parameter, so there's no need to ask the user for it. - // - // Note that constructors in Clang are represented as functions with - // return-type = void. - if self.is_constructor() { - fndecl.inputs.remove(0); - fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), - Self)); - } - - let sig = ast::MethodSig { - unsafety: ast::Unsafety::Unsafe, - abi: Abi::Rust, - decl: P(fndecl), - generics: ast::Generics::default(), - constness: respan(ctx.span(), ast::Constness::NotConst), - }; - - let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, - ctx); - - let mut stmts = vec![]; - - // If it's a constructor, we need to insert an extra parameter with a - // variable called `__bindgen_tmp` we're going to create. - if self.is_constructor() { - let prefix = ctx.trait_prefix(); - let tmp_variable_decl = - quote_stmt!(ctx.ext_cx(), - let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) - .unwrap(); - stmts.push(tmp_variable_decl); - exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); - } else if !self.is_static() { - assert!(!exprs.is_empty()); - exprs[0] = quote_expr!(ctx.ext_cx(), self); - }; - - let call = aster::expr::ExprBuilder::new() - .call() - .id(function_name) - .with_args(exprs) - .build(); - - stmts.push(ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(call), - span: ctx.span(), - }); - - if self.is_constructor() { - stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); - } - - let block = ast::Block { - stmts: stmts, - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), - }; - - let mut attrs = vec![]; - attrs.push(attributes::inline()); - - let item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(&name), - vis: ast::Visibility::Public, - attrs: attrs, - node: ast::ImplItemKind::Method(sig, P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), - }; - - methods.push(item); - } -} - -/// A helper type to construct enums, either bitfield ones or rust-style ones. -enum EnumBuilder<'a> { - Rust(aster::item::ItemEnumBuilder), - Bitfield { - canonical_name: &'a str, - aster: P, - }, - Consts { aster: P }, -} - -impl<'a> EnumBuilder<'a> { - /// Create a new enum given an item builder, a canonical name, a name for - /// the representation, and whether it should be represented as a rust enum. - fn new(aster: aster::item::ItemBuilder, - name: &'a str, - repr: P, - bitfield_like: bool, - constify: bool) - -> Self { - if bitfield_like { - EnumBuilder::Bitfield { - canonical_name: name, - aster: aster.tuple_struct(name) - .field() - .pub_() - .build_ty(repr) - .build(), - } - } else if constify { - EnumBuilder::Consts { - aster: aster.type_(name).build_ty(repr), - } - } else { - EnumBuilder::Rust(aster.enum_(name)) - } - } - - /// Add a variant to this enum. - fn with_variant<'b>(self, - ctx: &BindgenContext, - variant: &EnumVariant, - mangling_prefix: Option<&String>, - rust_ty: P, - result: &mut CodegenResult<'b>) - -> Self { - let variant_name = ctx.rust_mangle(variant.name()); - let expr = aster::AstBuilder::new().expr(); - let expr = match variant.val() { - EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), - EnumVariantValue::Unsigned(v) => expr.uint(v), - }; - - match self { - EnumBuilder::Rust(b) => { - EnumBuilder::Rust(b.with_variant_(ast::Variant_ { - name: ctx.rust_ident(&*variant_name), - attrs: vec![], - data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), - disr_expr: Some(expr), - })) - } - EnumBuilder::Bitfield { canonical_name, .. } => { - let constant_name = match mangling_prefix { - Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) - } - None => variant_name, - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .call() - .id(canonical_name) - .arg() - .build(expr) - .build() - .build(rust_ty); - result.push(constant); - self - } - EnumBuilder::Consts { .. } => { - let constant_name = match mangling_prefix { - Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) - } - None => variant_name, - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .build(expr) - .build(rust_ty); - - result.push(constant); - self - } - } - } - - fn build<'b>(self, - ctx: &BindgenContext, - rust_ty: P, - result: &mut CodegenResult<'b>) - -> P { - match self { - EnumBuilder::Rust(b) => b.build(), - EnumBuilder::Bitfield { canonical_name, aster } => { - let rust_ty_name = ctx.rust_ident_raw(canonical_name); - let prefix = ctx.trait_prefix(); - - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { - type Output = Self; - - #[inline] - fn bitor(self, other: Self) -> Self { - $rust_ty_name(self.0 | other.0) - } - } - ) - .unwrap(); - - result.push(impl_); - aster - } - EnumBuilder::Consts { aster, .. } => aster, - } - } -} - -impl CodeGenerator for Enum { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let name = item.canonical_name(ctx); - let enum_ty = item.expect_type(); - let layout = enum_ty.layout(ctx); - - let repr = self.repr().map(|repr| ctx.resolve_type(repr)); - let repr = match repr { - Some(repr) => { - match *repr.canonical_type(ctx).kind() { - TypeKind::Int(int_kind) => int_kind, - _ => panic!("Unexpected type as enum repr"), - } - } - None => { - warn!("Guessing type of enum! Forward declarations of enums \ - shouldn't be legal!"); - IntKind::Int - } - }; - - let signed = repr.is_signed(); - let size = layout.map(|l| l.size) - .or_else(|| repr.known_size()) - .unwrap_or(0); - - let repr_name = match (signed, size) { - (true, 1) => "i8", - (false, 1) => "u8", - (true, 2) => "i16", - (false, 2) => "u16", - (true, 4) => "i32", - (false, 4) => "u32", - (true, 8) => "i64", - (false, 8) => "u64", - _ => { - warn!("invalid enum decl: signed: {}, size: {}", signed, size); - "i32" - } - }; - - let mut builder = aster::AstBuilder::new().item().pub_(); - - // FIXME(emilio): These should probably use the path so it can - // disambiguate between namespaces, just like is_opaque etc. - let is_bitfield = { - ctx.options().bitfield_enums.matches(&name) || - (enum_ty.name().is_none() && - self.variants() - .iter() - .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) - }; - - let is_constified_enum = { - ctx.options().constified_enums.matches(&name) || - (enum_ty.name().is_none() && - self.variants() - .iter() - .any(|v| ctx.options().constified_enums.matches(&v.name()))) - }; - - let is_rust_enum = !is_bitfield && !is_constified_enum; - - // FIXME: Rust forbids repr with empty enums. Remove this condition when - // this is allowed. - // - // TODO(emilio): Delegate this to the builders? - if is_rust_enum { - if !self.variants().is_empty() { - builder = builder.with_attr(attributes::repr(repr_name)); - } - } else if is_bitfield { - builder = builder.with_attr(attributes::repr("C")); - } - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - builder = builder.with_attr(attributes::doc(comment)); - } - } - - if !is_constified_enum { - let derives = attributes::derives(&["Debug", - "Copy", - "Clone", - "PartialEq", - "Eq", - "Hash"]); - - builder = builder.with_attr(derives); - } - - fn add_constant<'a>(enum_: &Type, - // Only to avoid recomputing every time. - enum_canonical_name: &str, - // May be the same as "variant" if it's because the - // enum is unnamed and we still haven't seen the - // value. - variant_name: &str, - referenced_name: &str, - enum_rust_ty: P, - result: &mut CodegenResult<'a>) { - let constant_name = if enum_.name().is_some() { - format!("{}_{}", enum_canonical_name, variant_name) - } else { - variant_name.into() - }; - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(constant_name) - .expr() - .path() - .ids(&[&*enum_canonical_name, referenced_name]) - .build() - .build(enum_rust_ty); - result.push(constant); - } - - let repr = self.repr() - .and_then(|repr| repr.try_to_rust_ty_or_opaque(ctx, &()).ok()) - .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); - - let mut builder = EnumBuilder::new(builder, - &name, - repr, - is_bitfield, - is_constified_enum); - - // A map where we keep a value -> variant relation. - let mut seen_values = HashMap::<_, String>::new(); - let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); - let is_toplevel = item.is_toplevel(ctx); - - // Used to mangle the constants we generate in the unnamed-enum case. - let parent_canonical_name = if is_toplevel { - None - } else { - Some(item.parent_id().canonical_name(ctx)) - }; - - let constant_mangling_prefix = if ctx.options().prepend_enum_name { - if enum_ty.name().is_none() { - parent_canonical_name.as_ref().map(|n| &*n) - } else { - Some(&name) - } - } else { - None - }; - - // NB: We defer the creation of constified variants, in case we find - // another variant with the same value (which is the common thing to - // do). - let mut constified_variants = VecDeque::new(); - - let mut iter = self.variants().iter().peekable(); - while let Some(variant) = iter.next() - .or_else(|| constified_variants.pop_front()) { - if variant.hidden() { - continue; - } - - if variant.force_constification() && iter.peek().is_some() { - constified_variants.push_back(variant); - continue; - } - - match seen_values.entry(variant.val()) { - Entry::Occupied(ref entry) => { - if is_rust_enum { - let variant_name = ctx.rust_mangle(variant.name()); - let mangled_name = if is_toplevel || - enum_ty.name().is_some() { - variant_name - } else { - let parent_name = parent_canonical_name.as_ref() - .unwrap(); - - Cow::Owned(format!("{}_{}", - parent_name, - variant_name)) - }; - - let existing_variant_name = entry.get(); - add_constant(enum_ty, - &name, - &*mangled_name, - existing_variant_name, - enum_rust_ty.clone(), - result); - } else { - builder = builder.with_variant(ctx, - variant, - constant_mangling_prefix, - enum_rust_ty.clone(), - result); - } - } - Entry::Vacant(entry) => { - builder = builder.with_variant(ctx, - variant, - constant_mangling_prefix, - enum_rust_ty.clone(), - result); - - let variant_name = ctx.rust_mangle(variant.name()); - - // If it's an unnamed enum, or constification is enforced, - // we also generate a constant so it can be properly - // accessed. - if (is_rust_enum && enum_ty.name().is_none()) || - variant.force_constification() { - let mangled_name = if is_toplevel { - variant_name.clone() - } else { - let parent_name = parent_canonical_name.as_ref() - .unwrap(); - - Cow::Owned(format!("{}_{}", - parent_name, - variant_name)) - }; - - add_constant(enum_ty, - &name, - &mangled_name, - &variant_name, - enum_rust_ty.clone(), - result); - } - - entry.insert(variant_name.into_owned()); - } - } - } - - let enum_ = builder.build(ctx, enum_rust_ty, result); - result.push(enum_); - } -} - -/// Fallible conversion to an opaque blob. -/// -/// Implementors of this trait should provide the `try_get_layout` method to -/// fallibly get this thing's layout, which the provided `try_to_opaque` trait -/// method will use to convert the `Layout` into an opaque blob Rust type. -trait TryToOpaque { - type Extra; - - /// Get the layout for this thing, if one is available. - fn try_get_layout(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result; - - /// Do not override this provided trait method. - fn try_to_opaque(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result> { - self.try_get_layout(ctx, extra) - .map(|layout| BlobTyBuilder::new(layout).build()) - } -} - -/// Infallible conversion of an IR thing to an opaque blob. -/// -/// The resulting layout is best effort, and is unfortunately not guaranteed to -/// be correct. When all else fails, we fall back to a single byte layout as a -/// last resort, because C++ does not permit zero-sized types. See the note in -/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits -/// and when each is appropriate. -/// -/// Don't implement this directly. Instead implement `TryToOpaque`, and then -/// leverage the blanket impl for this trait. -trait ToOpaque: TryToOpaque { - fn get_layout(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> Layout { - self.try_get_layout(ctx, extra) - .unwrap_or_else(|_| Layout::for_size(1)) - } - - fn to_opaque(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> P { - let layout = self.get_layout(ctx, extra); - BlobTyBuilder::new(layout).build() - } -} - -impl ToOpaque for T - where T: TryToOpaque -{} - -/// Fallible conversion from an IR thing to an *equivalent* Rust type. -/// -/// If the C/C++ construct represented by the IR thing cannot (currently) be -/// represented in Rust (for example, instantiations of templates with -/// const-value generic parameters) then the impl should return an `Err`. It -/// should *not* attempt to return an opaque blob with the correct size and -/// alignment. That is the responsibility of the `TryToOpaque` trait. -trait TryToRustTy { - type Extra; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - extra: &Self::Extra) - -> error::Result>; -} - -/// Fallible conversion to a Rust type or an opaque blob with the correct size -/// and alignment. -/// -/// Don't implement this directly. Instead implement `TryToRustTy` and -/// `TryToOpaque`, and then leverage the blanket impl for this trait below. -trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { - type Extra; - - fn try_to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &::Extra) - -> error::Result>; -} - -impl TryToRustTyOrOpaque for T - where T: TryToRustTy + TryToOpaque -{ - type Extra = E; - - fn try_to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &E) - -> error::Result> { - self.try_to_rust_ty(ctx, extra) - .or_else(|_| { - if let Ok(layout) = self.try_get_layout(ctx, extra) { - Ok(BlobTyBuilder::new(layout).build()) - } else { - Err(error::Error::NoLayoutForOpaqueBlob) - } - }) - } -} - -/// Infallible conversion to a Rust type, or an opaque blob with a best effort -/// of correct size and alignment. -/// -/// Don't implement this directly. Instead implement `TryToRustTy` and -/// `TryToOpaque`, and then leverage the blanket impl for this trait below. -/// -/// ### Fallible vs. Infallible Conversions to Rust Types -/// -/// When should one use this infallible `ToRustTyOrOpaque` trait versus the -/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait -/// implementations that need to convert another thing into a Rust type or -/// opaque blob in a nested manner should also use fallible trait methods and -/// propagate failure up the stack. Only infallible functions and methods like -/// CodeGenerator implementations should use the infallible -/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely -/// we are to get a usable `Layout` even if we can't generate an equivalent Rust -/// type for a C++ construct. -trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { - type Extra; - - fn to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &::Extra) - -> P; -} - -impl ToRustTyOrOpaque for T - where T: TryToRustTy + ToOpaque -{ - type Extra = E; - - fn to_rust_ty_or_opaque(&self, - ctx: &BindgenContext, - extra: &E) - -> P { - self.try_to_rust_ty(ctx, extra) - .unwrap_or_else(|_| self.to_opaque(ctx, extra)) - } -} - -impl TryToOpaque for ItemId { - type Extra = (); - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result { - ctx.resolve_item(*self).try_get_layout(ctx, &()) - } -} - -impl TryToRustTy for ItemId { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) - } -} - -impl TryToOpaque for Item { - type Extra = (); - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result { - self.kind().expect_type().try_get_layout(ctx, self) - } -} - -impl TryToRustTy for Item { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - self.kind().expect_type().try_to_rust_ty(ctx, self) - } -} - -impl TryToOpaque for Type { - type Extra = Item; - - fn try_get_layout(&self, - ctx: &BindgenContext, - _: &Item) - -> error::Result { - self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) - } -} - -impl TryToRustTy for Type { - type Extra = Item; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - item: &Item) - -> error::Result> { - use self::helpers::ast_ty::*; - - match *self.kind() { - TypeKind::Void => Ok(raw_type(ctx, "c_void")), - // TODO: we should do something smart with nullptr, or maybe *const - // c_void is enough? - TypeKind::NullPtr => { - Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) - } - TypeKind::Int(ik) => { - match ik { - IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), - IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), - IntKind::SChar => Ok(raw_type(ctx, "c_schar")), - IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), - IntKind::Short => Ok(raw_type(ctx, "c_short")), - IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), - IntKind::Int => Ok(raw_type(ctx, "c_int")), - IntKind::UInt => Ok(raw_type(ctx, "c_uint")), - IntKind::Long => Ok(raw_type(ctx, "c_long")), - IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), - IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), - IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), - - IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), - IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), - IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), - IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), - IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), - IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), - IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), - IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), - IntKind::Custom { name, .. } => { - let ident = ctx.rust_ident_raw(name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) - } - // FIXME: This doesn't generate the proper alignment, but we - // can't do better right now. We should be able to use - // i128/u128 when they're available. - IntKind::U128 | IntKind::I128 => { - Ok(aster::ty::TyBuilder::new().array(2).u64()) - } - } - } - TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), - TypeKind::Complex(fk) => { - let float_path = float_kind_rust_type(ctx, fk); - - ctx.generated_bindegen_complex(); - Ok(if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) - } else { - quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) - }) - } - TypeKind::Function(ref fs) => { - // We can't rely on the sizeof(Option>) == - // sizeof(NonZero<_>) optimization with opaque blobs (because - // they aren't NonZero), so don't *ever* use an or_opaque - // variant here. - let ty = fs.try_to_rust_ty(ctx, &())?; - - let prefix = ctx.trait_prefix(); - Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) - } - TypeKind::Array(item, len) => { - let ty = item.try_to_rust_ty(ctx, &())?; - Ok(aster::ty::TyBuilder::new().array(len).build(ty)) - } - TypeKind::Enum(..) => { - let path = item.namespace_aware_canonical_path(ctx); - Ok(aster::AstBuilder::new() - .ty() - .path() - .ids(path) - .build()) - } - TypeKind::TemplateInstantiation(ref inst) => { - inst.try_to_rust_ty(ctx, self) - } - TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), - TypeKind::TemplateAlias(inner, _) | - TypeKind::Alias(inner) => { - let template_params = item.used_template_params(ctx) - .unwrap_or(vec![]) - .into_iter() - .filter(|param| param.is_named(ctx, &())) - .collect::>(); - - let spelling = self.name().expect("Unnamed alias?"); - if item.is_opaque(ctx) && !template_params.is_empty() { - self.try_to_opaque(ctx, item) - } else if let Some(ty) = utils::type_from_named(ctx, - spelling, - inner) { - Ok(ty) - } else { - utils::build_templated_path(item, ctx, template_params) - } - } - TypeKind::Comp(ref info) => { - let template_params = item.used_template_params(ctx); - if info.has_non_type_template_params() || - (item.is_opaque(ctx) && template_params.is_some()) { - return self.try_to_opaque(ctx, item); - } - - let template_params = template_params.unwrap_or(vec![]); - utils::build_templated_path(item, - ctx, - template_params) - } - TypeKind::Opaque => { - self.try_to_opaque(ctx, item) - } - TypeKind::BlockPointer => { - let void = raw_type(ctx, "c_void"); - Ok(void.to_ptr(/* is_const = */ - false, - ctx.span())) - } - TypeKind::Pointer(inner) | - TypeKind::Reference(inner) => { - let inner = ctx.resolve_item(inner); - let inner_ty = inner.expect_type(); - - // Regardless if we can properly represent the inner type, we - // should always generate a proper pointer here, so use - // infallible conversion of the inner type. - let ty = inner.to_rust_ty_or_opaque(ctx, &()); - - // Avoid the first function pointer level, since it's already - // represented in Rust. - if inner_ty.canonical_type(ctx).is_function() { - Ok(ty) - } else { - let is_const = self.is_const() || - inner.expect_type().is_const(); - Ok(ty.to_ptr(is_const, ctx.span())) - } - } - TypeKind::Named => { - let name = item.canonical_name(ctx); - let ident = ctx.rust_ident(&name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) - } - TypeKind::ObjCSel => Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)), - TypeKind::ObjCId | - TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), - ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) - } - } - } -} - -impl TryToOpaque for TemplateInstantiation { - type Extra = Type; - - fn try_get_layout(&self, - ctx: &BindgenContext, - self_ty: &Type) - -> error::Result { - self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) - } -} - -impl TryToRustTy for TemplateInstantiation { - type Extra = Type; - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &Type) - -> error::Result> { - let decl = self.template_definition(); - let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); - - let decl_params = match decl.self_template_params(ctx) { - Some(params) => params, - None => { - // This can happen if we generated an opaque type for a partial - // template specialization, and we've hit an instantiation of - // that partial specialization. - extra_assert!(ctx.resolve_type_through_type_refs(decl) - .is_opaque()); - return Err(error::Error::InstantiationOfOpaqueType); - } - }; - - // TODO: If the decl type is a template class/struct - // declaration's member template declaration, it could rely on - // generic template parameters from its outer template - // class/struct. When we emit bindings for it, it could require - // *more* type arguments than we have here, and we will need to - // reconstruct them somehow. We don't have any means of doing - // that reconstruction at this time. - - if let ast::TyKind::Path(_, ref mut path) = ty.node { - let template_args = self.template_arguments() - .iter() - .zip(decl_params.iter()) - // Only pass type arguments for the type parameters that - // the decl uses. - .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) - .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) - .collect::>>()?; - - path.segments.last_mut().unwrap().parameters = if - template_args.is_empty() { - None - } else { - Some(P(ast::PathParameters::AngleBracketed( - ast::AngleBracketedParameterData { - lifetimes: vec![], - types: template_args, - bindings: vec![], - } - ))) - } - } - - Ok(P(ty)) - } -} - -impl TryToRustTy for FunctionSig { - type Extra = (); - - fn try_to_rust_ty(&self, - ctx: &BindgenContext, - _: &()) - -> error::Result> { - // TODO: we might want to consider ignoring the reference return value. - let ret = utils::fnsig_return_ty(ctx, &self); - let arguments = utils::fnsig_arguments(ctx, &self); - - let decl = P(ast::FnDecl { - inputs: arguments, - output: ret, - variadic: self.is_variadic(), - }); - - let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: self.abi().expect("Invalid abi for function!"), - lifetimes: vec![], - decl: decl, - })); - - Ok(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: fnty, - span: ctx.span(), - })) - } -} - -impl CodeGenerator for Function { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - item: &Item) { - debug!("::codegen: item = {:?}", item); - - let name = self.name(); - let mut canonical_name = item.canonical_name(ctx); - let mangled_name = self.mangled_name(); - - { - let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); - - // TODO: Maybe warn here if there's a type/argument mismatch, or - // something? - if result.seen_function(seen_symbol_name) { - return; - } - result.saw_function(seen_symbol_name); - } - - let signature_item = ctx.resolve_item(self.signature()); - let signature = signature_item.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("Signature kind is not a Function: {:?}", signature), - }; - - let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); - - let mut attributes = vec![]; - - if ctx.options().generate_comments { - if let Some(comment) = item.comment() { - attributes.push(attributes::doc(comment)); - } - } - - if let Some(mangled) = mangled_name { - attributes.push(attributes::link_name(mangled)); - } else if name != canonical_name { - attributes.push(attributes::link_name(name)); - } - - let foreign_item_kind = - ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); - - // Handle overloaded functions by giving each overload its own unique - // suffix. - let times_seen = result.overload_number(&canonical_name); - if times_seen > 0 { - write!(&mut canonical_name, "{}", times_seen).unwrap(); - } - - let foreign_item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attributes, - node: foreign_item_kind, - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, - }; - - let item = ForeignModBuilder::new(signature.abi() - .expect("Invalid abi for function!")) - .with_foreign_item(foreign_item) - .build(ctx); - - result.push(item); - } -} - - -fn objc_method_codegen(ctx: &BindgenContext, - method: &ObjCMethod, - class_name: Option<&str>) - -> (ast::ImplItem, ast::TraitItem) { - let signature = method.signature(); - let fn_args = utils::fnsig_arguments(ctx, signature); - let fn_ret = utils::fnsig_return_ty(ctx, signature); - - let sig = if method.is_class_method() { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .with_args(fn_args.clone()) - .build(fn_ret) - } else { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .self_() - .build(ast::SelfKind::Value(ast::Mutability::Immutable)) - .with_args(fn_args.clone()) - .build(fn_ret) - }; - - // Collect the actual used argument names - let arg_names: Vec<_> = fn_args.iter() - .map(|ref arg| match arg.pat.node { - ast::PatKind::Ident(_, ref spanning, _) => { - spanning.node.name.as_str().to_string() - } - _ => { - panic!("odd argument!"); - } - }) - .collect(); - - let methods_and_args = - ctx.rust_ident(&method.format_method_call(&arg_names)); - - let body = if method.is_class_method() { - let class_name = - class_name.expect("Generating a class method without class name?") - .to_owned(); - let expect_msg = format!("Couldn't find {}", class_name); - quote_stmt!(ctx.ext_cx(), - msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args]) - .unwrap() - } else { - quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap() - }; - let block = ast::Block { - stmts: vec![body], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), - }; - - let attrs = vec![]; - - let impl_item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(method.rust_name()), - vis: ast::Visibility::Inherited, // Public, - attrs: attrs.clone(), - node: ast::ImplItemKind::Method(sig.clone(), P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), - }; - - let trait_item = ast::TraitItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(method.rust_name()), - attrs: attrs, - node: ast::TraitItemKind::Method(sig, None), - span: ctx.span(), - }; - - (impl_item, trait_item) -} - -impl CodeGenerator for ObjCInterface { - type Extra = Item; - - fn codegen<'a>(&self, - ctx: &BindgenContext, - result: &mut CodegenResult<'a>, - _whitelisted_items: &ItemSet, - _: &Item) { - let mut impl_items = vec![]; - let mut trait_items = vec![]; - - for method in self.methods() { - let (impl_item, trait_item) = - objc_method_codegen(ctx, method, None); - impl_items.push(impl_item); - trait_items.push(trait_item) - } - - for class_method in self.class_methods() { - let (impl_item, trait_item) = - objc_method_codegen(ctx, class_method, Some(self.name())); - impl_items.push(impl_item); - trait_items.push(trait_item) - } - - let trait_name = self.rust_name(); - - let trait_block = aster::AstBuilder::new() - .item() - .pub_() - .trait_(&trait_name) - .with_items(trait_items) - .build(); - - let ty_for_impl = quote_ty!(ctx.ext_cx(), id); - let impl_block = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id(&trait_name) - .build() - .with_items(impl_items) - .build_ty(ty_for_impl); - - result.push(trait_block); - result.push(impl_block); - result.saw_objc(); - } -} - - - -pub fn codegen(context: &mut BindgenContext) -> Vec> { - context.gen(|context| { - let counter = Cell::new(0); - let mut result = CodegenResult::new(&counter); - - debug!("codegen: {:?}", context.options()); - - let whitelisted_items: ItemSet = context.whitelisted_items().collect(); - - if context.options().emit_ir { - for &id in whitelisted_items.iter() { - let item = context.resolve_item(id); - println!("ir: {:?} = {:#?}", id, item); - } - } - - if let Some(path) = context.options().emit_ir_graphviz.as_ref() { - match dot::write_dot_file(context, path) { - Ok(()) => info!("Your dot file was generated successfully into: {}", path), - Err(e) => error!("{}", e), - } - } - - context.resolve_item(context.root_module()) - .codegen(context, &mut result, &whitelisted_items, &()); - - result.items - }) -} - -mod utils { - use super::{error, TryToRustTy, ToRustTyOrOpaque}; - use aster; - use ir::context::{BindgenContext, ItemId}; - use ir::function::FunctionSig; - use ir::item::{Item, ItemCanonicalPath}; - use ir::ty::TypeKind; - use std::mem; - use syntax::ast; - use syntax::ptr::P; - - pub fn prepend_objc_header(ctx: &BindgenContext, - result: &mut Vec>) { - let use_objc = if ctx.options().objc_extern_crate { - quote_item!(ctx.ext_cx(), - use objc; - ) - .unwrap() - } else { - quote_item!(ctx.ext_cx(), - #[macro_use] - extern crate objc; - ) - .unwrap() - }; - - - let id_type = quote_item!(ctx.ext_cx(), - #[allow(non_camel_case_types)] - pub type id = *mut objc::runtime::Object; - ) - .unwrap(); - - let items = vec![use_objc, id_type]; - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_union_types(ctx: &BindgenContext, - result: &mut Vec>) { - let prefix = ctx.trait_prefix(); - - // TODO(emilio): The fmt::Debug impl could be way nicer with - // std::intrinsics::type_name, but... - let union_field_decl = quote_item!(ctx.ext_cx(), - #[repr(C)] - pub struct __BindgenUnionField( - ::$prefix::marker::PhantomData); - ) - .unwrap(); - - let union_field_impl = quote_item!(&ctx.ext_cx(), - impl __BindgenUnionField { - #[inline] - pub fn new() -> Self { - __BindgenUnionField(::$prefix::marker::PhantomData) - } - - #[inline] - pub unsafe fn as_ref(&self) -> &T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { - ::$prefix::mem::transmute(self) - } - } - ) - .unwrap(); - - let union_field_default_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::default::Default for __BindgenUnionField { - #[inline] - fn default() -> Self { - Self::new() - } - } - ) - .unwrap(); - - let union_field_clone_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::clone::Clone for __BindgenUnionField { - #[inline] - fn clone(&self) -> Self { - Self::new() - } - } - ) - .unwrap(); - - let union_field_copy_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::marker::Copy for __BindgenUnionField {} - ) - .unwrap(); - - let union_field_debug_impl = quote_item!(ctx.ext_cx(), - impl ::$prefix::fmt::Debug for __BindgenUnionField { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { - fmt.write_str("__BindgenUnionField") - } - } - ) - .unwrap(); - - let items = vec![union_field_decl, - union_field_impl, - union_field_default_impl, - union_field_clone_impl, - union_field_copy_impl, - union_field_debug_impl]; - - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_incomplete_array_types(ctx: &BindgenContext, - result: &mut Vec>) { - let prefix = ctx.trait_prefix(); - - let incomplete_array_decl = quote_item!(ctx.ext_cx(), - #[repr(C)] - #[derive(Default)] - pub struct __IncompleteArrayField( - ::$prefix::marker::PhantomData); - ) - .unwrap(); - - let incomplete_array_impl = quote_item!(&ctx.ext_cx(), - impl __IncompleteArrayField { - #[inline] - pub fn new() -> Self { - __IncompleteArrayField(::$prefix::marker::PhantomData) - } - - #[inline] - pub unsafe fn as_ptr(&self) -> *const T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_mut_ptr(&mut self) -> *mut T { - ::$prefix::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_slice(&self, len: usize) -> &[T] { - ::$prefix::slice::from_raw_parts(self.as_ptr(), len) - } - - #[inline] - pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { - ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) - } - } - ) - .unwrap(); - - let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), - impl ::$prefix::fmt::Debug for __IncompleteArrayField { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { - fmt.write_str("__IncompleteArrayField") - } - } - ) - .unwrap(); - - let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::clone::Clone for __IncompleteArrayField { - #[inline] - fn clone(&self) -> Self { - Self::new() - } - } - ) - .unwrap(); - - let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), - impl ::$prefix::marker::Copy for __IncompleteArrayField {} - ) - .unwrap(); - - let items = vec![incomplete_array_decl, - incomplete_array_impl, - incomplete_array_debug_impl, - incomplete_array_clone_impl, - incomplete_array_copy_impl]; - - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn prepend_complex_type(ctx: &BindgenContext, - result: &mut Vec>) { - let complex_type = quote_item!(ctx.ext_cx(), - #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] - #[repr(C)] - pub struct __BindgenComplex { - pub re: T, - pub im: T - } - ) - .unwrap(); - - let items = vec![complex_type]; - let old_items = mem::replace(result, items); - result.extend(old_items.into_iter()); - } - - pub fn build_templated_path(item: &Item, - ctx: &BindgenContext, - template_params: Vec) - -> error::Result> { - let path = item.namespace_aware_canonical_path(ctx); - let builder = aster::AstBuilder::new().ty().path(); - - let template_params = template_params.iter() - .map(|param| param.try_to_rust_ty(ctx, &())) - .collect::>>()?; - - // XXX: I suck at aster. - if path.len() == 1 { - return Ok(builder.segment(&path[0]) - .with_tys(template_params) - .build() - .build()); - } - - let mut builder = builder.id(&path[0]); - for (i, segment) in path.iter().skip(1).enumerate() { - // Take into account the skip(1) - builder = if i == path.len() - 2 { - // XXX Extra clone courtesy of the borrow checker. - builder.segment(&segment) - .with_tys(template_params.clone()) - .build() - } else { - builder.segment(&segment).build() - } - } - - Ok(builder.build()) - } - - fn primitive_ty(ctx: &BindgenContext, name: &str) -> P { - let ident = ctx.rust_ident_raw(&name); - quote_ty!(ctx.ext_cx(), $ident) - } - - pub fn type_from_named(ctx: &BindgenContext, - name: &str, - _inner: ItemId) - -> Option> { - // FIXME: We could use the inner item to check this is really a - // primitive type but, who the heck overrides these anyway? - Some(match name { - "int8_t" => primitive_ty(ctx, "i8"), - "uint8_t" => primitive_ty(ctx, "u8"), - "int16_t" => primitive_ty(ctx, "i16"), - "uint16_t" => primitive_ty(ctx, "u16"), - "int32_t" => primitive_ty(ctx, "i32"), - "uint32_t" => primitive_ty(ctx, "u32"), - "int64_t" => primitive_ty(ctx, "i64"), - "uint64_t" => primitive_ty(ctx, "u64"), - - "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), - - "intptr_t" | "ptrdiff_t" | "ssize_t" => { - primitive_ty(ctx, "isize") - } - _ => return None, - }) - } - - pub fn rust_fndecl_from_signature(ctx: &BindgenContext, - sig: &Item) - -> P { - let signature = sig.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How?"), - }; - - let decl_ty = signature.try_to_rust_ty(ctx, &()) - .expect("function signature to Rust type conversion is infallible"); - match decl_ty.unwrap().node { - ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, - _ => panic!("How did this happen exactly?"), - } - } - - pub fn fnsig_return_ty(ctx: &BindgenContext, - sig: &FunctionSig) - -> ast::FunctionRetTy { - let return_item = ctx.resolve_item(sig.return_type()); - if let TypeKind::Void = *return_item.kind().expect_type().kind() { - ast::FunctionRetTy::Default(ctx.span()) - } else { - ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) - } - } - - pub fn fnsig_arguments(ctx: &BindgenContext, - sig: &FunctionSig) - -> Vec { - use super::ToPtr; - let mut unnamed_arguments = 0; - sig.argument_types().iter().map(|&(ref name, ty)| { - let arg_item = ctx.resolve_item(ty); - let arg_ty = arg_item.kind().expect_type(); - - // From the C90 standard[1]: - // - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - // - // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html - let arg_ty = match *arg_ty.canonical_type(ctx).kind() { - TypeKind::Array(t, _) => { - t.to_rust_ty_or_opaque(ctx, &()) - .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) - }, - TypeKind::Pointer(inner) => { - let inner = ctx.resolve_item(inner); - let inner_ty = inner.expect_type(); - if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { - quote_ty!(ctx.ext_cx(), id) - } else { - arg_item.to_rust_ty_or_opaque(ctx, &()) - } - }, - _ => { - arg_item.to_rust_ty_or_opaque(ctx, &()) - } - }; - - let arg_name = match *name { - Some(ref name) => ctx.rust_mangle(name).into_owned(), - None => { - unnamed_arguments += 1; - format!("arg{}", unnamed_arguments) - } - }; - - assert!(!arg_name.is_empty()); - - ast::Arg { - ty: arg_ty, - pat: aster::AstBuilder::new().pat().id(arg_name), - id: ast::DUMMY_NODE_ID, - } - }).collect::>() - } -} +mod error; +mod helpers; +mod struct_layout; + +use self::helpers::{BlobTyBuilder, attributes}; +use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; +use self::struct_layout::{align_to, bytes_from_bits}; +use aster; + +use ir::annotations::FieldAccessorKind; +use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; +use ir::context::{BindgenContext, ItemId}; +use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use ir::dot; +use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; +use ir::function::{Function, FunctionSig}; +use ir::int::IntKind; +use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath, + ItemSet}; +use ir::item_kind::ItemKind; +use ir::layout::Layout; +use ir::module::Module; +use ir::objc::{ObjCInterface, ObjCMethod}; +use ir::template::{AsNamed, TemplateInstantiation}; +use ir::ty::{TemplateDeclaration, Type, TypeKind}; +use ir::var::Var; + +use std::borrow::Cow; +use std::cell::Cell; +use std::cmp; +use std::collections::{HashSet, VecDeque}; +use std::collections::hash_map::{Entry, HashMap}; +use std::fmt::Write; +use std::mem; +use std::ops; +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{Span, respan}; +use syntax::ptr::P; + +fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { + if !ctx.options().enable_cxx_namespaces { + return 0; + } + + item.ancestors(ctx) + .filter(|id| ctx.resolve_item(*id).is_module()) + .fold(1, |i, _| i + 1) +} + +fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec { + let mut path = vec![ctx.rust_ident_raw("self")]; + + if ctx.options().enable_cxx_namespaces { + let super_ = ctx.rust_ident_raw("super"); + + for _ in 0..root_import_depth(ctx, item) { + path.push(super_.clone()); + } + } + + path +} + +fn root_import(ctx: &BindgenContext, module: &Item) -> P { + assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); + assert!(module.is_module()); + + let mut path = top_level_path(ctx, module); + + let root = ctx.root_module().canonical_name(ctx); + let root_ident = ctx.rust_ident(&root); + path.push(root_ident); + + let use_root = aster::AstBuilder::new() + .item() + .use_() + .ids(path) + .build() + .build(); + + quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() +} + +struct CodegenResult<'a> { + items: Vec>, + + /// A monotonic counter used to add stable unique id's to stuff that doesn't + /// need to be referenced by anything. + codegen_id: &'a Cell, + + /// Whether an union has been generated at least once. + saw_union: bool, + + /// Whether an incomplete array has been generated at least once. + saw_incomplete_array: bool, + + /// Whether Objective C types have been seen at least once. + saw_objc: bool, + + items_seen: HashSet, + /// The set of generated function/var names, needed because in C/C++ is + /// legal to do something like: + /// + /// ```c++ + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// ``` + /// + /// Being these two different declarations. + functions_seen: HashSet, + vars_seen: HashSet, + + /// Used for making bindings to overloaded functions. Maps from a canonical + /// function name to the number of overloads we have already codegen'd for + /// that name. This lets us give each overload a unique suffix. + overload_counters: HashMap, +} + +impl<'a> CodegenResult<'a> { + fn new(codegen_id: &'a Cell) -> Self { + CodegenResult { + items: vec![], + saw_union: false, + saw_incomplete_array: false, + saw_objc: false, + codegen_id: codegen_id, + items_seen: Default::default(), + functions_seen: Default::default(), + vars_seen: Default::default(), + overload_counters: Default::default(), + } + } + + fn saw_union(&mut self) { + self.saw_union = true; + } + + fn saw_incomplete_array(&mut self) { + self.saw_incomplete_array = true; + } + + fn saw_objc(&mut self) { + self.saw_objc = true; + } + + fn seen(&self, item: ItemId) -> bool { + self.items_seen.contains(&item) + } + + fn set_seen(&mut self, item: ItemId) { + self.items_seen.insert(item); + } + + fn seen_function(&self, name: &str) -> bool { + self.functions_seen.contains(name) + } + + fn saw_function(&mut self, name: &str) { + self.functions_seen.insert(name.into()); + } + + /// Get the overload number for the given function name. Increments the + /// counter internally so the next time we ask for the overload for this + /// name, we get the incremented value, and so on. + fn overload_number(&mut self, name: &str) -> u32 { + let mut counter = + self.overload_counters.entry(name.into()).or_insert(0); + let number = *counter; + *counter += 1; + number + } + + fn seen_var(&self, name: &str) -> bool { + self.vars_seen.contains(name) + } + + fn saw_var(&mut self, name: &str) { + self.vars_seen.insert(name.into()); + } + + fn inner(&mut self, cb: F) -> Vec> + where F: FnOnce(&mut Self), + { + let mut new = Self::new(self.codegen_id); + + cb(&mut new); + + self.saw_union |= new.saw_union; + self.saw_incomplete_array |= new.saw_incomplete_array; + self.saw_objc |= new.saw_objc; + + new.items + } +} + +impl<'a> ops::Deref for CodegenResult<'a> { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl<'a> ops::DerefMut for CodegenResult<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +struct ForeignModBuilder { + inner: ast::ForeignMod, +} + +impl ForeignModBuilder { + fn new(abi: Abi) -> Self { + ForeignModBuilder { + inner: ast::ForeignMod { + abi: abi, + items: vec![], + }, + } + } + + fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { + self.inner.items.push(item); + self + } + + #[allow(dead_code)] + fn with_foreign_items(mut self, items: I) -> Self + where I: IntoIterator, + { + self.inner.items.extend(items.into_iter()); + self + } + + fn build(self, ctx: &BindgenContext) -> P { + use syntax::codemap::DUMMY_SP; + P(ast::Item { + ident: ctx.rust_ident(""), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::ForeignMod(self.inner), + vis: ast::Visibility::Public, + attrs: vec![], + span: DUMMY_SP, + }) + } +} + +/// A trait to convert a rust type into a pointer, optionally const, to the same +/// type. +/// +/// This is done due to aster's lack of pointer builder, I guess I should PR +/// there. +trait ToPtr { + fn to_ptr(self, is_const: bool, span: Span) -> P; +} + +impl ToPtr for P { + fn to_ptr(self, is_const: bool, span: Span) -> Self { + let ty = ast::TyKind::Ptr(ast::MutTy { + ty: self, + mutbl: if is_const { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }, + }); + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ty, + span: span, + }) + } +} + +trait CodeGenerator { + /// Extra information from the caller. + type Extra; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + extra: &Self::Extra); +} + +impl CodeGenerator for Item { + type Extra = (); + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _extra: &()) { + if self.is_hidden(ctx) || result.seen(self.id()) { + debug!("::codegen: Ignoring hidden or seen: \ + self = {:?}", + self); + return; + } + + debug!("::codegen: self = {:?}", self); + if !whitelisted_items.contains(&self.id()) { + // TODO(emilio, #453): Figure out what to do when this happens + // legitimately, we could track the opaque stuff and disable the + // assertion there I guess. + error!("Found non-whitelisted item in code generation: {:?}", self); + } + + result.set_seen(self.id()); + + match *self.kind() { + ItemKind::Module(ref module) => { + module.codegen(ctx, result, whitelisted_items, self); + } + ItemKind::Function(ref fun) => { + if ctx.options().codegen_config.functions { + fun.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Var(ref var) => { + if ctx.options().codegen_config.vars { + var.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Type(ref ty) => { + if ctx.options().codegen_config.types { + ty.codegen(ctx, result, whitelisted_items, self); + } + } + } + } +} + +impl CodeGenerator for Module { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let codegen_self = |result: &mut CodegenResult, + found_any: &mut bool| { + for child in self.children() { + if whitelisted_items.contains(child) { + *found_any = true; + ctx.resolve_item(*child) + .codegen(ctx, result, whitelisted_items, &()); + } + } + + if item.id() == ctx.root_module() { + if result.saw_union && !ctx.options().unstable_rust { + utils::prepend_union_types(ctx, &mut *result); + } + if result.saw_incomplete_array { + utils::prepend_incomplete_array_types(ctx, &mut *result); + } + if ctx.need_bindegen_complex_type() { + utils::prepend_complex_type(ctx, &mut *result); + } + if result.saw_objc { + utils::prepend_objc_header(ctx, &mut *result); + } + } + }; + + if !ctx.options().enable_cxx_namespaces || + (self.is_inline() && !ctx.options().conservative_inline_namespaces) { + codegen_self(result, &mut false); + return; + } + + let mut found_any = false; + let inner_items = result.inner(|result| { + result.push(root_import(ctx, item)); + codegen_self(result, &mut found_any); + }); + + // Don't bother creating an empty module. + if !found_any { + return; + } + + let module = ast::ItemKind::Mod(ast::Mod { + inner: ctx.span(), + items: inner_items, + }); + + let name = item.canonical_name(ctx); + let item_builder = aster::AstBuilder::new() + .item() + .pub_(); + let item = if name == "root" { + let attrs = &["non_snake_case", + "non_camel_case_types", + "non_upper_case_globals"]; + item_builder.with_attr(attributes::allow(attrs)) + .build_item_kind(name, module) + } else { + item_builder.build_item_kind(name, module) + }; + + result.push(item); + } +} + +impl CodeGenerator for Var { + type Extra = Item; + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + use ir::var::VarType; + debug!("::codegen: item = {:?}", item); + + let canonical_name = item.canonical_name(ctx); + + if result.seen_var(&canonical_name) { + return; + } + result.saw_var(&canonical_name); + + let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + + if let Some(val) = self.val() { + let const_item = aster::AstBuilder::new() + .item() + .pub_() + .const_(canonical_name) + .expr(); + let item = match *val { + VarType::Bool(val) => { + const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) + } + VarType::Int(val) => { + const_item.build(helpers::ast_ty::int_expr(val)).build(ty) + } + VarType::String(ref bytes) => { + // Account the trailing zero. + // + // TODO: Here we ignore the type we just made up, probably + // we should refactor how the variable type and ty id work. + let len = bytes.len() + 1; + let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); + + match String::from_utf8(bytes.clone()) { + Ok(string) => { + const_item.build(helpers::ast_ty::cstr_expr(string)) + .build(quote_ty!(ctx.ext_cx(), &'static $ty)) + } + Err(..) => { + const_item + .build(helpers::ast_ty::byte_array_expr(bytes)) + .build(ty) + } + } + } + VarType::Float(f) => { + match helpers::ast_ty::float_expr(ctx, f) { + Ok(expr) => { + const_item.build(expr).build(ty) + } + Err(..) => return, + } + } + VarType::Char(c) => { + const_item + .build(aster::AstBuilder::new().expr().lit().byte(c)) + .build(ty) + } + }; + + result.push(item); + } else { + let mut attrs = vec![]; + if let Some(mangled) = self.mangled_name() { + attrs.push(attributes::link_name(mangled)); + } else if canonical_name != self.name() { + attrs.push(attributes::link_name(self.name())); + } + + let item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attrs, + node: ast::ForeignItemKind::Static(ty, !self.is_const()), + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(Abi::C) + .with_foreign_item(item) + .build(ctx); + result.push(item); + } + } +} + +impl CodeGenerator for Type { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + match *self.kind() { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Array(..) | + TypeKind::Pointer(..) | + TypeKind::BlockPointer | + TypeKind::Reference(..) | + TypeKind::Function(..) | + TypeKind::ResolvedTypeRef(..) | + TypeKind::Opaque | + TypeKind::Named => { + // These items don't need code generation, they only need to be + // converted to rust types in fields, arguments, and such. + return; + } + TypeKind::TemplateInstantiation(ref inst) => { + inst.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::Comp(ref ci) => { + ci.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::TemplateAlias(inner, _) | + TypeKind::Alias(inner) => { + let inner_item = ctx.resolve_item(inner); + let name = item.canonical_name(ctx); + + // Try to catch the common pattern: + // + // typedef struct foo { ... } foo; + // + // here. + // + if inner_item.canonical_name(ctx) == name { + return; + } + + // If this is a known named type, disallow generating anything + // for it too. + let spelling = self.name().expect("Unnamed alias?"); + if utils::type_from_named(ctx, spelling, inner).is_some() { + return; + } + + let mut used_template_params = item.used_template_params(ctx); + let inner_rust_type = if item.is_opaque(ctx) { + used_template_params = None; + self.to_opaque(ctx, item) + } else { + // Its possible that we have better layout information than + // the inner type does, so fall back to an opaque blob based + // on our layout if converting the inner item fails. + inner_item.try_to_rust_ty_or_opaque(ctx, &()) + .unwrap_or_else(|_| self.to_opaque(ctx, item)) + }; + + { + // FIXME(emilio): This is a workaround to avoid generating + // incorrect type aliases because of types that we haven't + // been able to resolve (because, eg, they depend on a + // template parameter). + // + // It's kind of a shame not generating them even when they + // could be referenced, but we already do the same for items + // with invalid template parameters, and at least this way + // they can be replaced, instead of generating plain invalid + // code. + let inner_canon_type = inner_item.expect_type() + .canonical_type(ctx); + if inner_canon_type.is_invalid_named_type() { + warn!("Item contained invalid named type, skipping: \ + {:?}, {:?}", + item, + inner_item); + return; + } + } + + let rust_name = ctx.rust_ident(&name); + let mut typedef = aster::AstBuilder::new().item().pub_(); + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + typedef = typedef.attr().doc(comment); + } + } + + // We prefer using `pub use` over `pub type` because of: + // https://github.com/rust-lang/rust/issues/26264 + let simple_enum_path = match inner_rust_type.node { + ast::TyKind::Path(None, ref p) => { + if used_template_params.is_none() && + inner_item.expect_type() + .canonical_type(ctx) + .is_enum() && + p.segments.iter().all(|p| p.parameters.is_none()) { + Some(p.clone()) + } else { + None + } + } + _ => None, + }; + + let typedef = if let Some(mut p) = simple_enum_path { + for ident in top_level_path(ctx, item).into_iter().rev() { + p.segments.insert(0, + ast::PathSegment { + identifier: ident, + parameters: None, + }); + } + typedef.use_().build(p).as_(rust_name) + } else { + let mut generics = typedef.type_(rust_name).generics(); + if let Some(ref params) = used_template_params { + for template_param in params { + if let Some(id) = + template_param.as_named(ctx, &()) { + let template_param = ctx.resolve_type(id); + if template_param.is_invalid_named_type() { + warn!("Item contained invalid template \ + parameter: {:?}", + item); + return; + } + generics = + generics.ty_param_id(template_param.name() + .unwrap()); + } + } + } + generics.build().build_ty(inner_rust_type) + }; + result.push(typedef) + } + TypeKind::Enum(ref ei) => { + ei.codegen(ctx, result, whitelisted_items, item) + } + TypeKind::ObjCId | TypeKind::ObjCSel => { + result.saw_objc(); + } + TypeKind::ObjCInterface(ref interface) => { + interface.codegen(ctx, result, whitelisted_items, item) + } + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +struct Vtable<'a> { + item_id: ItemId, + #[allow(dead_code)] + methods: &'a [Method], + #[allow(dead_code)] + base_classes: &'a [Base], +} + +impl<'a> Vtable<'a> { + fn new(item_id: ItemId, + methods: &'a [Method], + base_classes: &'a [Base]) + -> Self { + Vtable { + item_id: item_id, + methods: methods, + base_classes: base_classes, + } + } +} + +impl<'a> CodeGenerator for Vtable<'a> { + type Extra = Item; + + fn codegen<'b>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'b>, + _whitelisted_items: &ItemSet, + item: &Item) { + assert_eq!(item.id(), self.item_id); + // For now, generate an empty struct, later we should generate function + // pointers and whatnot. + let attributes = vec![attributes::repr("C")]; + + let vtable = aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .tuple_struct(self.canonical_name(ctx)) + .field() + .build_ty(helpers::ast_ty::raw_type(ctx, "c_void")) + .build(); + result.push(vtable); + } +} + +impl<'a> ItemCanonicalName for Vtable<'a> { + fn canonical_name(&self, ctx: &BindgenContext) -> String { + format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) + } +} + +impl<'a> TryToRustTy for Vtable<'a> { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) -> error::Result> { + Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) + } +} + +struct Bitfield<'a> { + index: &'a mut usize, + fields: Vec<&'a Field>, +} + +impl<'a> Bitfield<'a> { + fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self { + Bitfield { + index: index, + fields: fields, + } + } + + fn codegen_fields(self, + ctx: &BindgenContext, + parent: &CompInfo, + fields: &mut Vec, + methods: &mut Vec) + -> Layout { + // NOTE: What follows is reverse-engineered from LLVM's + // lib/AST/RecordLayoutBuilder.cpp + // + // FIXME(emilio): There are some differences between Microsoft and the + // Itanium ABI, but we'll ignore those and stick to Itanium for now. + // + // Also, we need to handle packed bitfields and stuff. + // TODO(emilio): Take into account C++'s wide bitfields, and + // packing, sigh. + let mut total_size_in_bits = 0; + let mut max_align = 0; + let mut unfilled_bits_in_last_unit = 0; + let mut field_size_in_bits = 0; + *self.index += 1; + let mut last_field_name = format!("_bitfield_{}", self.index); + let mut last_field_align = 0; + + // (name, mask, width, bitfield's type, bitfield's layout) + let mut bitfields: Vec<(&str, usize, usize, ast::Ty, Layout)> = vec![]; + + for field in self.fields { + let width = field.bitfield().unwrap() as usize; + let field_item = ctx.resolve_item(field.ty()); + let field_ty_layout = field_item.kind() + .expect_type() + .layout(ctx) + .expect("Bitfield without layout? Gah!"); + let field_align = field_ty_layout.align; + + if field_size_in_bits != 0 && + (width == 0 || width > unfilled_bits_in_last_unit) { + // We've finished a physical field, so flush it and its bitfields. + field_size_in_bits = align_to(field_size_in_bits, field_align); + fields.push(flush_bitfields(ctx, + parent, + field_size_in_bits, + last_field_align, + &last_field_name, + bitfields.drain(..), + methods)); + + // TODO(emilio): dedup this. + *self.index += 1; + last_field_name = format!("_bitfield_{}", self.index); + + // Now reset the size and the rest of stuff. + // unfilled_bits_in_last_unit = 0; + field_size_in_bits = 0; + last_field_align = 0; + } + + if let Some(name) = field.name() { + let field_item_ty = field_item.to_rust_ty_or_opaque(ctx, &()); + bitfields.push((name, + field_size_in_bits, + width, + field_item_ty.unwrap(), + field_ty_layout)); + } + + field_size_in_bits += width; + total_size_in_bits += width; + + let data_size = align_to(field_size_in_bits, field_align * 8); + + max_align = cmp::max(max_align, field_align); + + // NB: The width here is completely, absolutely intentional. + last_field_align = cmp::max(last_field_align, width); + + unfilled_bits_in_last_unit = data_size - field_size_in_bits; + } + + if field_size_in_bits != 0 { + // Flush the last physical field and its bitfields. + fields.push(flush_bitfields(ctx, + parent, + field_size_in_bits, + last_field_align, + &last_field_name, + bitfields.drain(..), + methods)); + } + + Layout::new(bytes_from_bits(total_size_in_bits), max_align) + } +} + +fn parent_has_method(ctx: &BindgenContext, + parent: &CompInfo, + name: &str) + -> bool { + parent.methods().iter().any(|method| { + let method_name = match *ctx.resolve_item(method.signature()).kind() { + ItemKind::Function(ref func) => func.name(), + ref otherwise => panic!("a method's signature should always be a \ + item of kind ItemKind::Function, found: \ + {:?}", + otherwise), + }; + + method_name == name || ctx.rust_mangle(&method_name) == name + }) +} + +fn bitfield_getter_name(ctx: &BindgenContext, + parent: &CompInfo, + bitfield_name: &str) + -> ast::Ident { + let name = ctx.rust_mangle(bitfield_name); + + if parent_has_method(ctx, parent, &name) { + let mut name = name.to_string(); + name.push_str("_bindgen_bitfield"); + return ctx.ext_cx().ident_of(&name); + } + + ctx.ext_cx().ident_of(&name) +} + +fn bitfield_setter_name(ctx: &BindgenContext, + parent: &CompInfo, + bitfield_name: &str) + -> ast::Ident { + let setter = format!("set_{}", bitfield_name); + let mut setter = ctx.rust_mangle(&setter).to_string(); + + if parent_has_method(ctx, parent, &setter) { + setter.push_str("_bindgen_bitfield"); + } + + ctx.ext_cx().ident_of(&setter) +} + +/// A physical field (which is a word or byte or ...) has many logical bitfields +/// contained within it, but not all bitfields are in the same physical field of +/// a struct. This function creates a single physical field and flushes all the +/// accessors for the logical `bitfields` within that physical field to the +/// outgoing `methods`. +fn flush_bitfields<'a, I>(ctx: &BindgenContext, + parent: &CompInfo, + field_size_in_bits: usize, + field_align: usize, + field_name: &str, + bitfields: I, + methods: &mut Vec) -> ast::StructField + where I: IntoIterator +{ + use aster::struct_field::StructFieldBuilder; + + let field_layout = Layout::new(bytes_from_bits_pow2(field_size_in_bits), + bytes_from_bits_pow2(field_align)); + let field_ty = BlobTyBuilder::new(field_layout).build(); + + let field = StructFieldBuilder::named(field_name) + .pub_() + .build_ty(field_ty.clone()); + + let field_int_ty = match field_layout.size { + 8 => quote_ty!(ctx.ext_cx(), u64), + 4 => quote_ty!(ctx.ext_cx(), u32), + 2 => quote_ty!(ctx.ext_cx(), u16), + 1 => quote_ty!(ctx.ext_cx(), u8), + _ => return field + }; + + for (name, offset, width, bitfield_ty, bitfield_layout) in bitfields { + let prefix = ctx.trait_prefix(); + let getter_name = bitfield_getter_name(ctx, parent, name); + let setter_name = bitfield_setter_name(ctx, parent, name); + let field_ident = ctx.ext_cx().ident_of(field_name); + + let bitfield_int_ty = BlobTyBuilder::new(bitfield_layout).build(); + + let mask: usize = ((1usize << width) - 1usize) << offset; + + let impl_item = quote_item!( + ctx.ext_cx(), + impl XxxIgnored { + #[inline] + pub fn $getter_name(&self) -> $bitfield_ty { + let mask = $mask as $field_int_ty; + let field_val: $field_int_ty = unsafe { + ::$prefix::mem::transmute(self.$field_ident) + }; + let val = (field_val & mask) >> $offset; + unsafe { + ::$prefix::mem::transmute(val as $bitfield_int_ty) + } + } + + #[inline] + pub fn $setter_name(&mut self, val: $bitfield_ty) { + let mask = $mask as $field_int_ty; + let val = val as $bitfield_int_ty as $field_int_ty; + + let mut field_val: $field_int_ty = unsafe { + ::$prefix::mem::transmute(self.$field_ident) + }; + field_val &= !mask; + field_val |= (val << $offset) & mask; + + self.$field_ident = unsafe { + ::$prefix::mem::transmute(field_val) + }; + } + } + ).unwrap(); + + match impl_item.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, items) => { + methods.extend(items.into_iter()); + }, + _ => unreachable!(), + }; + } + + field +} + +impl CodeGenerator for TemplateInstantiation { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + // Although uses of instantiations don't need code generation, and are + // just converted to rust types in fields, vars, etc, we take this + // opportunity to generate tests for their layout here. + if !ctx.options().layout_tests { + return + } + + let layout = item.kind().expect_type().layout(ctx); + + if let Some(layout) = layout { + let size = layout.size; + let align = layout.align; + + let name = item.canonical_name(ctx); + let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", + name, + item.id().as_usize()); + let fn_name = ctx.rust_ident_raw(&fn_name); + + let prefix = ctx.trait_prefix(); + let ident = item.to_rust_ty_or_opaque(ctx, &()); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + + let item = quote_item!( + ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size, + concat!("Size of template specialization: ", stringify!($ident))); + assert_eq!($align_of_expr, $align, + concat!("Alignment of template specialization: ", stringify!($ident))); + }) + .unwrap(); + + result.push(item); + } + } +} + +impl CodeGenerator for CompInfo { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + use aster::struct_field::StructFieldBuilder; + + debug!("::codegen: item = {:?}", item); + + // Don't output classes with template parameters that aren't types, and + // also don't output template specializations, neither total or partial. + if self.has_non_type_template_params() { + return; + } + + let used_template_params = item.used_template_params(ctx); + + // generate tuple struct if struct or union is a forward declaration, + // skip for now if template parameters are needed. + if self.is_forward_declaration() && used_template_params.is_none() { + let struct_name = item.canonical_name(ctx); + let struct_name = ctx.rust_ident_raw(&struct_name); + let tuple_struct = quote_item!(ctx.ext_cx(), + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct $struct_name([u8; 0]); + ) + .unwrap(); + result.push(tuple_struct); + return; + } + + let mut attributes = vec![]; + let mut needs_clone_impl = false; + let mut needs_default_impl = false; + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + } + if self.packed() { + attributes.push(attributes::repr_list(&["C", "packed"])); + } else { + attributes.push(attributes::repr("C")); + } + + let is_union = self.kind() == CompKind::Union; + let mut derives = vec![]; + if item.can_derive_debug(ctx, ()) { + derives.push("Debug"); + } + + if item.can_derive_default(ctx, ()) { + derives.push("Default"); + } else { + needs_default_impl = ctx.options().derive_default; + } + + if item.can_derive_copy(ctx, ()) && + !item.annotations().disallow_copy() { + derives.push("Copy"); + if used_template_params.is_some() { + // FIXME: This requires extra logic if you have a big array in a + // templated struct. The reason for this is that the magic: + // fn clone(&self) -> Self { *self } + // doesn't work for templates. + // + // It's not hard to fix though. + derives.push("Clone"); + } else { + needs_clone_impl = true; + } + } + + if !derives.is_empty() { + attributes.push(attributes::derives(&derives)) + } + + let canonical_name = item.canonical_name(ctx); + let builder = if is_union && ctx.options().unstable_rust { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .union_(&canonical_name) + } else { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .struct_(&canonical_name) + }; + + // Generate the vtable from the method list if appropriate. + // + // TODO: I don't know how this could play with virtual methods that are + // not in the list of methods found by us, we'll see. Also, could the + // order of the vtable pointers vary? + // + // FIXME: Once we generate proper vtables, we need to codegen the + // vtable, but *not* generate a field for it in the case that + // needs_explicit_vtable is false but has_vtable is true. + // + // Also, we need to generate the vtable in such a way it "inherits" from + // the parent too. + let mut fields = vec![]; + let mut struct_layout = StructLayoutTracker::new(ctx, self); + if self.needs_explicit_vtable(ctx) { + let vtable = + Vtable::new(item.id(), self.methods(), self.base_members()); + vtable.codegen(ctx, result, whitelisted_items, item); + + let vtable_type = vtable.try_to_rust_ty(ctx, &()) + .expect("vtable to Rust type conversion is infallible") + .to_ptr(true, ctx.span()); + + let vtable_field = StructFieldBuilder::named("vtable_") + .pub_() + .build_ty(vtable_type); + + struct_layout.saw_vtable(); + + fields.push(vtable_field); + } + + for (i, base) in self.base_members().iter().enumerate() { + // Virtual bases are already taken into account by the vtable + // pointer. + // + // FIXME(emilio): Is this always right? + if base.is_virtual() { + continue; + } + + let base_ty = ctx.resolve_type(base.ty); + // NB: We won't include unsized types in our base chain because they + // would contribute to our size given the dummy field we insert for + // unsized types. + if base_ty.is_unsized(ctx) { + continue; + } + + let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); + let field_name = if i == 0 { + "_base".into() + } else { + format!("_base_{}", i) + }; + + struct_layout.saw_base(base_ty); + + let field = StructFieldBuilder::named(field_name) + .pub_() + .build_ty(inner); + fields.push(field); + } + if is_union { + result.saw_union(); + } + + let layout = item.kind().expect_type().layout(ctx); + + let mut current_bitfield_width = None; + let mut current_bitfield_layout: Option = None; + let mut current_bitfield_fields = vec![]; + let mut bitfield_count = 0; + let struct_fields = self.fields(); + let fields_should_be_private = item.annotations() + .private_fields() + .unwrap_or(false); + let struct_accessor_kind = item.annotations() + .accessor_kind() + .unwrap_or(FieldAccessorKind::None); + + let mut methods = vec![]; + let mut anonymous_field_count = 0; + for field in struct_fields { + debug_assert_eq!(current_bitfield_width.is_some(), + current_bitfield_layout.is_some()); + debug_assert_eq!(current_bitfield_width.is_some(), + !current_bitfield_fields.is_empty()); + + let field_ty = ctx.resolve_type(field.ty()); + + // Try to catch a bitfield contination early. + if let (Some(ref mut bitfield_width), Some(width)) = + (current_bitfield_width, field.bitfield()) { + let layout = current_bitfield_layout.unwrap(); + debug!("Testing bitfield continuation {} {} {:?}", + *bitfield_width, + width, + layout); + if *bitfield_width + width <= (layout.size * 8) as u32 { + *bitfield_width += width; + current_bitfield_fields.push(field); + continue; + } + } + + // Flush the current bitfield. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = + mem::replace(&mut current_bitfield_fields, vec![]); + let bitfield_layout = Bitfield::new(&mut bitfield_count, + bitfield_fields) + .codegen_fields(ctx, self, &mut fields, &mut methods); + struct_layout.saw_bitfield_batch(bitfield_layout); + + current_bitfield_width = None; + current_bitfield_layout = None; + } + debug_assert!(current_bitfield_fields.is_empty()); + + if let Some(width) = field.bitfield() { + let layout = field_ty.layout(ctx) + .expect("Bitfield type without layout?"); + current_bitfield_width = Some(width); + current_bitfield_layout = Some(layout); + current_bitfield_fields.push(field); + continue; + } + + let ty = field.ty().to_rust_ty_or_opaque(ctx, &()); + + // NB: In unstable rust we use proper `union` types. + let ty = if is_union && !ctx.options().unstable_rust { + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) + } + } else if let Some(item) = + field_ty.is_incomplete_array(ctx) { + result.saw_incomplete_array(); + + let inner = item.to_rust_ty_or_opaque(ctx, &()); + + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) + } else { + quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) + } + } else { + ty + }; + + let mut attrs = vec![]; + if ctx.options().generate_comments { + if let Some(comment) = field.comment() { + attrs.push(attributes::doc(comment)); + } + } + let field_name = match field.name() { + Some(name) => ctx.rust_mangle(name).into_owned(), + None => { + anonymous_field_count += 1; + format!("__bindgen_anon_{}", anonymous_field_count) + } + }; + + if !is_union { + if let Some(padding_field) = + struct_layout.pad_field(&field_name, field_ty, field.offset()) { + fields.push(padding_field); + } + } + + let is_private = field.annotations() + .private_fields() + .unwrap_or(fields_should_be_private); + + let accessor_kind = field.annotations() + .accessor_kind() + .unwrap_or(struct_accessor_kind); + + let mut field = StructFieldBuilder::named(&field_name); + + if !is_private { + field = field.pub_(); + } + + let field = field.with_attrs(attrs) + .build_ty(ty.clone()); + + fields.push(field); + + // TODO: Factor the following code out, please! + if accessor_kind == FieldAccessorKind::None { + continue; + } + + let getter_name = + ctx.rust_ident_raw(&format!("get_{}", field_name)); + let mutable_getter_name = + ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); + let field_name = ctx.rust_ident_raw(&field_name); + + let accessor_methods_impl = match accessor_kind { + FieldAccessorKind::None => unreachable!(), + FieldAccessorKind::Regular => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Unsafe => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub unsafe fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub unsafe fn $mutable_getter_name(&mut self) + -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Immutable => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + } + ) + } + }; + + match accessor_methods_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => { + methods.extend(items.clone()) + } + _ => unreachable!(), + } + } + + // Flush the last bitfield if any. + // + // FIXME: Reduce duplication with the loop above. + // FIXME: May need to pass current_bitfield_layout too. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = mem::replace(&mut current_bitfield_fields, + vec![]); + let bitfield_layout = Bitfield::new(&mut bitfield_count, + bitfield_fields) + .codegen_fields(ctx, self, &mut fields, &mut methods); + struct_layout.saw_bitfield_batch(bitfield_layout); + } + debug_assert!(current_bitfield_fields.is_empty()); + + if is_union && !ctx.options().unstable_rust { + let layout = layout.expect("Unable to get layout information?"); + let ty = BlobTyBuilder::new(layout).build(); + let field = StructFieldBuilder::named("bindgen_union_field") + .pub_() + .build_ty(ty); + + struct_layout.saw_union(layout); + + fields.push(field); + } + + // Yeah, sorry about that. + if item.is_opaque(ctx) { + fields.clear(); + methods.clear(); + + match layout { + Some(l) => { + let ty = BlobTyBuilder::new(l).build(); + let field = + StructFieldBuilder::named("_bindgen_opaque_blob") + .pub_() + .build_ty(ty); + fields.push(field); + } + None => { + warn!("Opaque type without layout! Expect dragons!"); + } + } + } else if !is_union && !self.is_unsized(ctx) { + if let Some(padding_field) = + layout.and_then(|layout| { + struct_layout.pad_struct(&canonical_name, layout) + }) { + fields.push(padding_field); + } + + if let Some(align_field) = + layout.and_then(|layout| struct_layout.align_struct(layout)) { + fields.push(align_field); + } + } + + // C++ requires every struct to be addressable, so what C++ compilers do + // is making the struct 1-byte sized. + // + // This is apparently not the case for C, see: + // https://github.com/servo/rust-bindgen/issues/551 + // + // Just get the layout, and assume C++ if not. + // + // NOTE: This check is conveniently here to avoid the dummy fields we + // may add for unused template parameters. + if self.is_unsized(ctx) { + let has_address = layout.map_or(true, |l| l.size != 0); + if has_address { + let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); + let field = StructFieldBuilder::named("_address") + .pub_() + .build_ty(ty); + fields.push(field); + } + } + + let mut generics = aster::AstBuilder::new().generics(); + + if let Some(ref params) = used_template_params { + for (idx, ty) in params.iter().enumerate() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); + let ident = ctx.rust_ident(name); + + generics = generics.ty_param_id(ident); + + let prefix = ctx.trait_prefix(); + let phantom_ty = quote_ty!( + ctx.ext_cx(), + ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); + let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) + .build_ty(phantom_ty); + fields.push(phantom_field); + } + } + + let generics = generics.build(); + + let rust_struct = builder.with_generics(generics.clone()) + .with_fields(fields) + .build(); + result.push(rust_struct); + + // Generate the inner types and all that stuff. + // + // TODO: In the future we might want to be smart, and use nested + // modules, and whatnot. + for ty in self.inner_types() { + let child_item = ctx.resolve_item(*ty); + // assert_eq!(child_item.parent_id(), item.id()); + child_item.codegen(ctx, result, whitelisted_items, &()); + } + + // NOTE: Some unexposed attributes (like alignment attributes) may + // affect layout, so we're bad and pray to the gods for avoid sending + // all the tests to shit when parsing things like max_align_t. + if self.found_unknown_attr() { + warn!("Type {} has an unkown attribute that may affect layout", + canonical_name); + } + + if used_template_params.is_none() { + for var in self.inner_vars() { + ctx.resolve_item(*var) + .codegen(ctx, result, whitelisted_items, &()); + } + + if ctx.options().layout_tests { + if let Some(layout) = layout { + let fn_name = format!("bindgen_test_layout_{}", canonical_name); + let fn_name = ctx.rust_ident_raw(&fn_name); + let type_name = ctx.rust_ident_raw(&canonical_name); + let prefix = ctx.trait_prefix(); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$type_name>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$type_name>()); + let size = layout.size; + let align = layout.align; + + let check_struct_align = if align > mem::size_of::<*mut ()>() { + // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready + None + } else { + quote_item!(ctx.ext_cx(), + assert_eq!($align_of_expr, + $align, + concat!("Alignment of ", stringify!($type_name))); + ) + }; + + // FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready + let too_many_base_vtables = self.base_members() + .iter() + .filter(|base| { + ctx.resolve_type(base.ty).has_vtable(ctx) + }) + .count() > 1; + + let should_skip_field_offset_checks = item.is_opaque(ctx) || + too_many_base_vtables; + + let check_field_offset = if should_skip_field_offset_checks { + None + } else { + let asserts = self.fields() + .iter() + .filter(|field| field.bitfield().is_none()) + .flat_map(|field| { + field.name().and_then(|name| { + field.offset().and_then(|offset| { + let field_offset = offset / 8; + let field_name = ctx.rust_ident(name); + + quote_item!(ctx.ext_cx(), + assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, + $field_offset, + concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); + ) + }) + }) + }).collect::>>(); + + Some(asserts) + }; + + let item = quote_item!(ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, + $size, + concat!("Size of: ", stringify!($type_name))); + + $check_struct_align + $check_field_offset + }) + .unwrap(); + result.push(item); + } + } + + let mut method_names = Default::default(); + if ctx.options().codegen_config.methods { + for method in self.methods() { + assert!(method.kind() != MethodKind::Constructor); + method.codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + + if ctx.options().codegen_config.constructors { + for sig in self.constructors() { + Method::new(MethodKind::Constructor, + *sig, + /* const */ + false) + .codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + + if ctx.options().codegen_config.destructors { + if let Some((is_virtual, destructor)) = self.destructor() { + let kind = if is_virtual { + MethodKind::VirtualDestructor + } else { + MethodKind::Destructor + }; + + Method::new(kind, destructor, false) + .codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + } + + // NB: We can't use to_rust_ty here since for opaque types this tries to + // use the specialization knowledge to generate a blob field. + let ty_for_impl = aster::AstBuilder::new() + .ty() + .path() + .segment(&canonical_name) + .with_generics(generics.clone()) + .build() + .build(); + + if needs_clone_impl { + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn clone(&self) -> Self { *self } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let clone_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Clone") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(clone_impl); + } + + if needs_default_impl { + let prefix = ctx.trait_prefix(); + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let default_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Default") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(default_impl); + } + + if !methods.is_empty() { + let methods = aster::AstBuilder::new() + .item() + .impl_() + .with_generics(generics) + .with_items(methods) + .build_ty(ty_for_impl); + result.push(methods); + } + } +} + +trait MethodCodegen { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + parent: &CompInfo); +} + +impl MethodCodegen for Method { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _parent: &CompInfo) { + if self.is_virtual() { + return; // FIXME + } + + // First of all, output the actual function. + let function_item = ctx.resolve_item(self.signature()); + function_item.codegen(ctx, result, whitelisted_items, &()); + + let function = function_item.expect_function(); + let signature_item = ctx.resolve_item(function.signature()); + let mut name = match self.kind() { + MethodKind::Constructor => "new".into(), + MethodKind::Destructor => "destruct".into(), + _ => function.name().to_owned(), + }; + + let signature = match *signature_item.expect_type().kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How in the world?"), + }; + + // Do not generate variadic methods, since rust does not allow + // implementing them, and we don't do a good job at it anyway. + if signature.is_variadic() { + return; + } + + let count = { + let mut count = method_names.entry(name.clone()) + .or_insert(0); + *count += 1; + *count - 1 + }; + + if count != 0 { + name.push_str(&count.to_string()); + } + + let function_name = function_item.canonical_name(ctx); + let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) + .unwrap(); + if !self.is_static() && !self.is_constructor() { + let mutability = if self.is_const() { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }; + + assert!(!fndecl.inputs.is_empty()); + + // FIXME: use aster here. + fndecl.inputs[0] = ast::Arg { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Rptr(None, ast::MutTy { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::ImplicitSelf, + span: ctx.span() + }), + mutbl: mutability, + }), + span: ctx.span(), + }), + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Ident( + ast::BindingMode::ByValue(ast::Mutability::Immutable), + respan(ctx.span(), ctx.ext_cx().ident_of("self")), + None + ), + span: ctx.span(), + }), + id: ast::DUMMY_NODE_ID, + }; + } + + // If it's a constructor, we always return `Self`, and we inject the + // "this" parameter, so there's no need to ask the user for it. + // + // Note that constructors in Clang are represented as functions with + // return-type = void. + if self.is_constructor() { + fndecl.inputs.remove(0); + fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), + Self)); + } + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Unsafe, + abi: Abi::Rust, + decl: P(fndecl), + generics: ast::Generics::default(), + constness: respan(ctx.span(), ast::Constness::NotConst), + }; + + let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, + ctx); + + let mut stmts = vec![]; + + // If it's a constructor, we need to insert an extra parameter with a + // variable called `__bindgen_tmp` we're going to create. + if self.is_constructor() { + let prefix = ctx.trait_prefix(); + let tmp_variable_decl = + quote_stmt!(ctx.ext_cx(), + let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) + .unwrap(); + stmts.push(tmp_variable_decl); + exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); + } else if !self.is_static() { + assert!(!exprs.is_empty()); + exprs[0] = quote_expr!(ctx.ext_cx(), self); + }; + + let call = aster::expr::ExprBuilder::new() + .call() + .id(function_name) + .with_args(exprs) + .build(); + + stmts.push(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(call), + span: ctx.span(), + }); + + if self.is_constructor() { + stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); + } + + let block = ast::Block { + stmts: stmts, + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let mut attrs = vec![]; + attrs.push(attributes::inline()); + + let item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(&name), + vis: ast::Visibility::Public, + attrs: attrs, + node: ast::ImplItemKind::Method(sig, P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + methods.push(item); + } +} + +/// A helper type to construct enums, either bitfield ones or rust-style ones. +enum EnumBuilder<'a> { + Rust(aster::item::ItemEnumBuilder), + Bitfield { + canonical_name: &'a str, + aster: P, + }, + Consts { aster: P }, +} + +impl<'a> EnumBuilder<'a> { + /// Create a new enum given an item builder, a canonical name, a name for + /// the representation, and whether it should be represented as a rust enum. + fn new(aster: aster::item::ItemBuilder, + name: &'a str, + repr: P, + bitfield_like: bool, + constify: bool) + -> Self { + if bitfield_like { + EnumBuilder::Bitfield { + canonical_name: name, + aster: aster.tuple_struct(name) + .field() + .pub_() + .build_ty(repr) + .build(), + } + } else if constify { + EnumBuilder::Consts { + aster: aster.type_(name).build_ty(repr), + } + } else { + EnumBuilder::Rust(aster.enum_(name)) + } + } + + /// Add a variant to this enum. + fn with_variant<'b>(self, + ctx: &BindgenContext, + variant: &EnumVariant, + mangling_prefix: Option<&String>, + rust_ty: P, + result: &mut CodegenResult<'b>) + -> Self { + let variant_name = ctx.rust_mangle(variant.name()); + let expr = aster::AstBuilder::new().expr(); + let expr = match variant.val() { + EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), + EnumVariantValue::Unsigned(v) => expr.uint(v), + }; + + match self { + EnumBuilder::Rust(b) => { + EnumBuilder::Rust(b.with_variant_(ast::Variant_ { + name: ctx.rust_ident(&*variant_name), + attrs: vec![], + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), + disr_expr: Some(expr), + })) + } + EnumBuilder::Bitfield { canonical_name, .. } => { + let constant_name = match mangling_prefix { + Some(prefix) => { + Cow::Owned(format!("{}_{}", prefix, variant_name)) + } + None => variant_name, + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*constant_name) + .expr() + .call() + .id(canonical_name) + .arg() + .build(expr) + .build() + .build(rust_ty); + result.push(constant); + self + } + EnumBuilder::Consts { .. } => { + let constant_name = match mangling_prefix { + Some(prefix) => { + Cow::Owned(format!("{}_{}", prefix, variant_name)) + } + None => variant_name, + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*constant_name) + .expr() + .build(expr) + .build(rust_ty); + + result.push(constant); + self + } + } + } + + fn build<'b>(self, + ctx: &BindgenContext, + rust_ty: P, + result: &mut CodegenResult<'b>) + -> P { + match self { + EnumBuilder::Rust(b) => b.build(), + EnumBuilder::Bitfield { canonical_name, aster } => { + let rust_ty_name = ctx.rust_ident_raw(canonical_name); + let prefix = ctx.trait_prefix(); + + let impl_ = quote_item!(ctx.ext_cx(), + impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { + type Output = Self; + + #[inline] + fn bitor(self, other: Self) -> Self { + $rust_ty_name(self.0 | other.0) + } + } + ) + .unwrap(); + + result.push(impl_); + aster + } + EnumBuilder::Consts { aster, .. } => aster, + } + } +} + +impl CodeGenerator for Enum { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let name = item.canonical_name(ctx); + let enum_ty = item.expect_type(); + let layout = enum_ty.layout(ctx); + + let repr = self.repr().map(|repr| ctx.resolve_type(repr)); + let repr = match repr { + Some(repr) => { + match *repr.canonical_type(ctx).kind() { + TypeKind::Int(int_kind) => int_kind, + _ => panic!("Unexpected type as enum repr"), + } + } + None => { + warn!("Guessing type of enum! Forward declarations of enums \ + shouldn't be legal!"); + IntKind::Int + } + }; + + let signed = repr.is_signed(); + let size = layout.map(|l| l.size) + .or_else(|| repr.known_size()) + .unwrap_or(0); + + let repr_name = match (signed, size) { + (true, 1) => "i8", + (false, 1) => "u8", + (true, 2) => "i16", + (false, 2) => "u16", + (true, 4) => "i32", + (false, 4) => "u32", + (true, 8) => "i64", + (false, 8) => "u64", + _ => { + warn!("invalid enum decl: signed: {}, size: {}", signed, size); + "i32" + } + }; + + let mut builder = aster::AstBuilder::new().item().pub_(); + + // FIXME(emilio): These should probably use the path so it can + // disambiguate between namespaces, just like is_opaque etc. + let is_bitfield = { + ctx.options().bitfield_enums.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) + }; + + let is_constified_enum = { + ctx.options().constified_enums.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().constified_enums.matches(&v.name()))) + }; + + let is_rust_enum = !is_bitfield && !is_constified_enum; + + // FIXME: Rust forbids repr with empty enums. Remove this condition when + // this is allowed. + // + // TODO(emilio): Delegate this to the builders? + if is_rust_enum { + if !self.variants().is_empty() { + builder = builder.with_attr(attributes::repr(repr_name)); + } + } else if is_bitfield { + builder = builder.with_attr(attributes::repr("C")); + } + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + builder = builder.with_attr(attributes::doc(comment)); + } + } + + if !is_constified_enum { + let derives = attributes::derives(&["Debug", + "Copy", + "Clone", + "PartialEq", + "Eq", + "Hash"]); + + builder = builder.with_attr(derives); + } + + fn add_constant<'a>(enum_: &Type, + // Only to avoid recomputing every time. + enum_canonical_name: &str, + // May be the same as "variant" if it's because the + // enum is unnamed and we still haven't seen the + // value. + variant_name: &str, + referenced_name: &str, + enum_rust_ty: P, + result: &mut CodegenResult<'a>) { + let constant_name = if enum_.name().is_some() { + format!("{}_{}", enum_canonical_name, variant_name) + } else { + variant_name.into() + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(constant_name) + .expr() + .path() + .ids(&[&*enum_canonical_name, referenced_name]) + .build() + .build(enum_rust_ty); + result.push(constant); + } + + let repr = self.repr() + .and_then(|repr| repr.try_to_rust_ty_or_opaque(ctx, &()).ok()) + .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); + + let mut builder = EnumBuilder::new(builder, + &name, + repr, + is_bitfield, + is_constified_enum); + + // A map where we keep a value -> variant relation. + let mut seen_values = HashMap::<_, String>::new(); + let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); + let is_toplevel = item.is_toplevel(ctx); + + // Used to mangle the constants we generate in the unnamed-enum case. + let parent_canonical_name = if is_toplevel { + None + } else { + Some(item.parent_id().canonical_name(ctx)) + }; + + let constant_mangling_prefix = if ctx.options().prepend_enum_name { + if enum_ty.name().is_none() { + parent_canonical_name.as_ref().map(|n| &*n) + } else { + Some(&name) + } + } else { + None + }; + + // NB: We defer the creation of constified variants, in case we find + // another variant with the same value (which is the common thing to + // do). + let mut constified_variants = VecDeque::new(); + + let mut iter = self.variants().iter().peekable(); + while let Some(variant) = iter.next() + .or_else(|| constified_variants.pop_front()) { + if variant.hidden() { + continue; + } + + if variant.force_constification() && iter.peek().is_some() { + constified_variants.push_back(variant); + continue; + } + + match seen_values.entry(variant.val()) { + Entry::Occupied(ref entry) => { + if is_rust_enum { + let variant_name = ctx.rust_mangle(variant.name()); + let mangled_name = if is_toplevel || + enum_ty.name().is_some() { + variant_name + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned(format!("{}_{}", + parent_name, + variant_name)) + }; + + let existing_variant_name = entry.get(); + add_constant(enum_ty, + &name, + &*mangled_name, + existing_variant_name, + enum_rust_ty.clone(), + result); + } else { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + } + } + Entry::Vacant(entry) => { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + + let variant_name = ctx.rust_mangle(variant.name()); + + // If it's an unnamed enum, or constification is enforced, + // we also generate a constant so it can be properly + // accessed. + if (is_rust_enum && enum_ty.name().is_none()) || + variant.force_constification() { + let mangled_name = if is_toplevel { + variant_name.clone() + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned(format!("{}_{}", + parent_name, + variant_name)) + }; + + add_constant(enum_ty, + &name, + &mangled_name, + &variant_name, + enum_rust_ty.clone(), + result); + } + + entry.insert(variant_name.into_owned()); + } + } + } + + let enum_ = builder.build(ctx, enum_rust_ty, result); + result.push(enum_); + } +} + +/// Fallible conversion to an opaque blob. +/// +/// Implementors of this trait should provide the `try_get_layout` method to +/// fallibly get this thing's layout, which the provided `try_to_opaque` trait +/// method will use to convert the `Layout` into an opaque blob Rust type. +trait TryToOpaque { + type Extra; + + /// Get the layout for this thing, if one is available. + fn try_get_layout(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result; + + /// Do not override this provided trait method. + fn try_to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result> { + self.try_get_layout(ctx, extra) + .map(|layout| BlobTyBuilder::new(layout).build()) + } +} + +/// Infallible conversion of an IR thing to an opaque blob. +/// +/// The resulting layout is best effort, and is unfortunately not guaranteed to +/// be correct. When all else fails, we fall back to a single byte layout as a +/// last resort, because C++ does not permit zero-sized types. See the note in +/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits +/// and when each is appropriate. +/// +/// Don't implement this directly. Instead implement `TryToOpaque`, and then +/// leverage the blanket impl for this trait. +trait ToOpaque: TryToOpaque { + fn get_layout(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> Layout { + self.try_get_layout(ctx, extra) + .unwrap_or_else(|_| Layout::for_size(1)) + } + + fn to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> P { + let layout = self.get_layout(ctx, extra); + BlobTyBuilder::new(layout).build() + } +} + +impl ToOpaque for T + where T: TryToOpaque +{} + +/// Fallible conversion from an IR thing to an *equivalent* Rust type. +/// +/// If the C/C++ construct represented by the IR thing cannot (currently) be +/// represented in Rust (for example, instantiations of templates with +/// const-value generic parameters) then the impl should return an `Err`. It +/// should *not* attempt to return an opaque blob with the correct size and +/// alignment. That is the responsibility of the `TryToOpaque` trait. +trait TryToRustTy { + type Extra; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result>; +} + +/// Fallible conversion to a Rust type or an opaque blob with the correct size +/// and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { + type Extra; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &::Extra) + -> error::Result>; +} + +impl TryToRustTyOrOpaque for T + where T: TryToRustTy + TryToOpaque +{ + type Extra = E; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> error::Result> { + self.try_to_rust_ty(ctx, extra) + .or_else(|_| { + if let Ok(layout) = self.try_get_layout(ctx, extra) { + Ok(BlobTyBuilder::new(layout).build()) + } else { + Err(error::Error::NoLayoutForOpaqueBlob) + } + }) + } +} + +/// Infallible conversion to a Rust type, or an opaque blob with a best effort +/// of correct size and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +/// +/// ### Fallible vs. Infallible Conversions to Rust Types +/// +/// When should one use this infallible `ToRustTyOrOpaque` trait versus the +/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait +/// implementations that need to convert another thing into a Rust type or +/// opaque blob in a nested manner should also use fallible trait methods and +/// propagate failure up the stack. Only infallible functions and methods like +/// CodeGenerator implementations should use the infallible +/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely +/// we are to get a usable `Layout` even if we can't generate an equivalent Rust +/// type for a C++ construct. +trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { + type Extra; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &::Extra) + -> P; +} + +impl ToRustTyOrOpaque for T + where T: TryToRustTy + ToOpaque +{ + type Extra = E; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> P { + self.try_to_rust_ty(ctx, extra) + .unwrap_or_else(|_| self.to_opaque(ctx, extra)) + } +} + +impl TryToOpaque for ItemId { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result { + ctx.resolve_item(*self).try_get_layout(ctx, &()) + } +} + +impl TryToRustTy for ItemId { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) + } +} + +impl TryToOpaque for Item { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result { + self.kind().expect_type().try_get_layout(ctx, self) + } +} + +impl TryToRustTy for Item { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + self.kind().expect_type().try_to_rust_ty(ctx, self) + } +} + +impl TryToOpaque for Type { + type Extra = Item; + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &Item) + -> error::Result { + self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for Type { + type Extra = Item; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + item: &Item) + -> error::Result> { + use self::helpers::ast_ty::*; + + match *self.kind() { + TypeKind::Void => Ok(raw_type(ctx, "c_void")), + // TODO: we should do something smart with nullptr, or maybe *const + // c_void is enough? + TypeKind::NullPtr => { + Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) + } + TypeKind::Int(ik) => { + match ik { + IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), + IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), + IntKind::SChar => Ok(raw_type(ctx, "c_schar")), + IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), + IntKind::Short => Ok(raw_type(ctx, "c_short")), + IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), + IntKind::Int => Ok(raw_type(ctx, "c_int")), + IntKind::UInt => Ok(raw_type(ctx, "c_uint")), + IntKind::Long => Ok(raw_type(ctx, "c_long")), + IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), + IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), + IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), + + IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), + IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), + IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), + IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), + IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), + IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), + IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), + IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), + IntKind::Custom { name, .. } => { + let ident = ctx.rust_ident_raw(name); + Ok(quote_ty!(ctx.ext_cx(), $ident)) + } + // FIXME: This doesn't generate the proper alignment, but we + // can't do better right now. We should be able to use + // i128/u128 when they're available. + IntKind::U128 | IntKind::I128 => { + Ok(aster::ty::TyBuilder::new().array(2).u64()) + } + } + } + TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), + TypeKind::Complex(fk) => { + let float_path = float_kind_rust_type(ctx, fk); + + ctx.generated_bindegen_complex(); + Ok(if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) + }) + } + TypeKind::Function(ref fs) => { + // We can't rely on the sizeof(Option>) == + // sizeof(NonZero<_>) optimization with opaque blobs (because + // they aren't NonZero), so don't *ever* use an or_opaque + // variant here. + let ty = fs.try_to_rust_ty(ctx, &())?; + + let prefix = ctx.trait_prefix(); + Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) + } + TypeKind::Array(item, len) => { + let ty = item.try_to_rust_ty(ctx, &())?; + Ok(aster::ty::TyBuilder::new().array(len).build(ty)) + } + TypeKind::Enum(..) => { + let path = item.namespace_aware_canonical_path(ctx); + Ok(aster::AstBuilder::new() + .ty() + .path() + .ids(path) + .build()) + } + TypeKind::TemplateInstantiation(ref inst) => { + inst.try_to_rust_ty(ctx, self) + } + TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), + TypeKind::TemplateAlias(inner, _) | + TypeKind::Alias(inner) => { + let template_params = item.used_template_params(ctx) + .unwrap_or(vec![]) + .into_iter() + .filter(|param| param.is_named(ctx, &())) + .collect::>(); + + let spelling = self.name().expect("Unnamed alias?"); + if item.is_opaque(ctx) && !template_params.is_empty() { + self.try_to_opaque(ctx, item) + } else if let Some(ty) = utils::type_from_named(ctx, + spelling, + inner) { + Ok(ty) + } else { + utils::build_templated_path(item, ctx, template_params) + } + } + TypeKind::Comp(ref info) => { + let template_params = item.used_template_params(ctx); + if info.has_non_type_template_params() || + (item.is_opaque(ctx) && template_params.is_some()) { + return self.try_to_opaque(ctx, item); + } + + let template_params = template_params.unwrap_or(vec![]); + utils::build_templated_path(item, + ctx, + template_params) + } + TypeKind::Opaque => { + self.try_to_opaque(ctx, item) + } + TypeKind::BlockPointer => { + let void = raw_type(ctx, "c_void"); + Ok(void.to_ptr(/* is_const = */ + false, + ctx.span())) + } + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + + // Regardless if we can properly represent the inner type, we + // should always generate a proper pointer here, so use + // infallible conversion of the inner type. + let ty = inner.to_rust_ty_or_opaque(ctx, &()); + + // Avoid the first function pointer level, since it's already + // represented in Rust. + if inner_ty.canonical_type(ctx).is_function() { + Ok(ty) + } else { + let is_const = self.is_const() || + inner.expect_type().is_const(); + Ok(ty.to_ptr(is_const, ctx.span())) + } + } + TypeKind::Named => { + let name = item.canonical_name(ctx); + let ident = ctx.rust_ident(&name); + Ok(quote_ty!(ctx.ext_cx(), $ident)) + } + TypeKind::ObjCSel => Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)), + TypeKind::ObjCId | + TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +impl TryToOpaque for TemplateInstantiation { + type Extra = Type; + + fn try_get_layout(&self, + ctx: &BindgenContext, + self_ty: &Type) + -> error::Result { + self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for TemplateInstantiation { + type Extra = Type; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &Type) + -> error::Result> { + let decl = self.template_definition(); + let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); + + let decl_params = match decl.self_template_params(ctx) { + Some(params) => params, + None => { + // This can happen if we generated an opaque type for a partial + // template specialization, and we've hit an instantiation of + // that partial specialization. + extra_assert!(ctx.resolve_type_through_type_refs(decl) + .is_opaque()); + return Err(error::Error::InstantiationOfOpaqueType); + } + }; + + // TODO: If the decl type is a template class/struct + // declaration's member template declaration, it could rely on + // generic template parameters from its outer template + // class/struct. When we emit bindings for it, it could require + // *more* type arguments than we have here, and we will need to + // reconstruct them somehow. We don't have any means of doing + // that reconstruction at this time. + + if let ast::TyKind::Path(_, ref mut path) = ty.node { + let template_args = self.template_arguments() + .iter() + .zip(decl_params.iter()) + // Only pass type arguments for the type parameters that + // the decl uses. + .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) + .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) + .collect::>>()?; + + path.segments.last_mut().unwrap().parameters = if + template_args.is_empty() { + None + } else { + Some(P(ast::PathParameters::AngleBracketed( + ast::AngleBracketedParameterData { + lifetimes: vec![], + types: template_args, + bindings: vec![], + } + ))) + } + } + + Ok(P(ty)) + } +} + +impl TryToRustTy for FunctionSig { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result> { + // TODO: we might want to consider ignoring the reference return value. + let ret = utils::fnsig_return_ty(ctx, &self); + let arguments = utils::fnsig_arguments(ctx, &self); + + let decl = P(ast::FnDecl { + inputs: arguments, + output: ret, + variadic: self.is_variadic(), + }); + + let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: self.abi().expect("Invalid abi for function!"), + lifetimes: vec![], + decl: decl, + })); + + Ok(P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: fnty, + span: ctx.span(), + })) + } +} + +impl CodeGenerator for Function { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("::codegen: item = {:?}", item); + + let name = self.name(); + let mut canonical_name = item.canonical_name(ctx); + let mangled_name = self.mangled_name(); + + { + let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); + + // TODO: Maybe warn here if there's a type/argument mismatch, or + // something? + if result.seen_function(seen_symbol_name) { + return; + } + result.saw_function(seen_symbol_name); + } + + let signature_item = ctx.resolve_item(self.signature()); + let signature = signature_item.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("Signature kind is not a Function: {:?}", signature), + }; + + let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); + + let mut attributes = vec![]; + + if ctx.options().generate_comments { + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + } + + if let Some(mangled) = mangled_name { + attributes.push(attributes::link_name(mangled)); + } else if name != canonical_name { + attributes.push(attributes::link_name(name)); + } + + let foreign_item_kind = + ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); + + // Handle overloaded functions by giving each overload its own unique + // suffix. + let times_seen = result.overload_number(&canonical_name); + if times_seen > 0 { + write!(&mut canonical_name, "{}", times_seen).unwrap(); + } + + let foreign_item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attributes, + node: foreign_item_kind, + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(signature.abi() + .expect("Invalid abi for function!")) + .with_foreign_item(foreign_item) + .build(ctx); + + result.push(item); + } +} + + +fn objc_method_codegen(ctx: &BindgenContext, + method: &ObjCMethod, + class_name: Option<&str>) + -> (ast::ImplItem, ast::TraitItem) { + let signature = method.signature(); + let fn_args = utils::fnsig_arguments(ctx, signature); + let fn_ret = utils::fnsig_return_ty(ctx, signature); + + let sig = if method.is_class_method() { + aster::AstBuilder::new() + .method_sig() + .unsafe_() + .fn_decl() + .with_args(fn_args.clone()) + .build(fn_ret) + } else { + aster::AstBuilder::new() + .method_sig() + .unsafe_() + .fn_decl() + .self_() + .build(ast::SelfKind::Value(ast::Mutability::Immutable)) + .with_args(fn_args.clone()) + .build(fn_ret) + }; + + // Collect the actual used argument names + let arg_names: Vec<_> = fn_args.iter() + .map(|ref arg| match arg.pat.node { + ast::PatKind::Ident(_, ref spanning, _) => { + spanning.node.name.as_str().to_string() + } + _ => { + panic!("odd argument!"); + } + }) + .collect(); + + let methods_and_args = + ctx.rust_ident(&method.format_method_call(&arg_names)); + + let body = if method.is_class_method() { + let class_name = + class_name.expect("Generating a class method without class name?") + .to_owned(); + let expect_msg = format!("Couldn't find {}", class_name); + quote_stmt!(ctx.ext_cx(), + msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args]) + .unwrap() + } else { + quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap() + }; + let block = ast::Block { + stmts: vec![body], + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let attrs = vec![]; + + let impl_item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + vis: ast::Visibility::Inherited, // Public, + attrs: attrs.clone(), + node: ast::ImplItemKind::Method(sig.clone(), P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + let trait_item = ast::TraitItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + attrs: attrs, + node: ast::TraitItemKind::Method(sig, None), + span: ctx.span(), + }; + + (impl_item, trait_item) +} + +impl CodeGenerator for ObjCInterface { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + _: &Item) { + let mut impl_items = vec![]; + let mut trait_items = vec![]; + + for method in self.methods() { + let (impl_item, trait_item) = + objc_method_codegen(ctx, method, None); + impl_items.push(impl_item); + trait_items.push(trait_item) + } + + for class_method in self.class_methods() { + let (impl_item, trait_item) = + objc_method_codegen(ctx, class_method, Some(self.name())); + impl_items.push(impl_item); + trait_items.push(trait_item) + } + + let trait_name = self.rust_name(); + + let trait_block = aster::AstBuilder::new() + .item() + .pub_() + .trait_(&trait_name) + .with_items(trait_items) + .build(); + + let ty_for_impl = quote_ty!(ctx.ext_cx(), id); + let impl_block = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id(&trait_name) + .build() + .with_items(impl_items) + .build_ty(ty_for_impl); + + result.push(trait_block); + result.push(impl_block); + result.saw_objc(); + } +} + + + +pub fn codegen(context: &mut BindgenContext) -> Vec> { + context.gen(|context| { + let counter = Cell::new(0); + let mut result = CodegenResult::new(&counter); + + debug!("codegen: {:?}", context.options()); + + let whitelisted_items: ItemSet = context.whitelisted_items().collect(); + + if context.options().emit_ir { + for &id in whitelisted_items.iter() { + let item = context.resolve_item(id); + println!("ir: {:?} = {:#?}", id, item); + } + } + + if let Some(path) = context.options().emit_ir_graphviz.as_ref() { + match dot::write_dot_file(context, path) { + Ok(()) => info!("Your dot file was generated successfully into: {}", path), + Err(e) => error!("{}", e), + } + } + + context.resolve_item(context.root_module()) + .codegen(context, &mut result, &whitelisted_items, &()); + + result.items + }) +} + +mod utils { + use super::{error, TryToRustTy, ToRustTyOrOpaque}; + use aster; + use ir::context::{BindgenContext, ItemId}; + use ir::function::FunctionSig; + use ir::item::{Item, ItemCanonicalPath}; + use ir::ty::TypeKind; + use std::mem; + use syntax::ast; + use syntax::ptr::P; + + pub fn prepend_objc_header(ctx: &BindgenContext, + result: &mut Vec>) { + let use_objc = if ctx.options().objc_extern_crate { + quote_item!(ctx.ext_cx(), + use objc; + ) + .unwrap() + } else { + quote_item!(ctx.ext_cx(), + #[macro_use] + extern crate objc; + ) + .unwrap() + }; + + + let id_type = quote_item!(ctx.ext_cx(), + #[allow(non_camel_case_types)] + pub type id = *mut objc::runtime::Object; + ) + .unwrap(); + + let items = vec![use_objc, id_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_union_types(ctx: &BindgenContext, + result: &mut Vec>) { + let prefix = ctx.trait_prefix(); + + // TODO(emilio): The fmt::Debug impl could be way nicer with + // std::intrinsics::type_name, but... + let union_field_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + pub struct __BindgenUnionField( + ::$prefix::marker::PhantomData); + ) + .unwrap(); + + let union_field_impl = quote_item!(&ctx.ext_cx(), + impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { + __BindgenUnionField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ref(&self) -> &T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + ::$prefix::mem::transmute(self) + } + } + ) + .unwrap(); + + let union_field_default_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_clone_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_copy_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::marker::Copy for __BindgenUnionField {} + ) + .unwrap(); + + let union_field_debug_impl = quote_item!(ctx.ext_cx(), + impl ::$prefix::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) + -> ::$prefix::fmt::Result { + fmt.write_str("__BindgenUnionField") + } + } + ) + .unwrap(); + + let items = vec![union_field_decl, + union_field_impl, + union_field_default_impl, + union_field_clone_impl, + union_field_copy_impl, + union_field_debug_impl]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_incomplete_array_types(ctx: &BindgenContext, + result: &mut Vec>) { + let prefix = ctx.trait_prefix(); + + let incomplete_array_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + #[derive(Default)] + pub struct __IncompleteArrayField( + ::$prefix::marker::PhantomData); + ) + .unwrap(); + + let incomplete_array_impl = quote_item!(&ctx.ext_cx(), + impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::$prefix::slice::from_raw_parts(self.as_ptr(), len) + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + } + ) + .unwrap(); + + let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), + impl ::$prefix::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) + -> ::$prefix::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } + } + ) + .unwrap(); + + let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ) + .unwrap(); + + let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), + impl ::$prefix::marker::Copy for __IncompleteArrayField {} + ) + .unwrap(); + + let items = vec![incomplete_array_decl, + incomplete_array_impl, + incomplete_array_debug_impl, + incomplete_array_clone_impl, + incomplete_array_copy_impl]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_complex_type(ctx: &BindgenContext, + result: &mut Vec>) { + let complex_type = quote_item!(ctx.ext_cx(), + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C)] + pub struct __BindgenComplex { + pub re: T, + pub im: T + } + ) + .unwrap(); + + let items = vec![complex_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn build_templated_path(item: &Item, + ctx: &BindgenContext, + template_params: Vec) + -> error::Result> { + let path = item.namespace_aware_canonical_path(ctx); + let builder = aster::AstBuilder::new().ty().path(); + + let template_params = template_params.iter() + .map(|param| param.try_to_rust_ty(ctx, &())) + .collect::>>()?; + + // XXX: I suck at aster. + if path.len() == 1 { + return Ok(builder.segment(&path[0]) + .with_tys(template_params) + .build() + .build()); + } + + let mut builder = builder.id(&path[0]); + for (i, segment) in path.iter().skip(1).enumerate() { + // Take into account the skip(1) + builder = if i == path.len() - 2 { + // XXX Extra clone courtesy of the borrow checker. + builder.segment(&segment) + .with_tys(template_params.clone()) + .build() + } else { + builder.segment(&segment).build() + } + } + + Ok(builder.build()) + } + + fn primitive_ty(ctx: &BindgenContext, name: &str) -> P { + let ident = ctx.rust_ident_raw(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + + pub fn type_from_named(ctx: &BindgenContext, + name: &str, + _inner: ItemId) + -> Option> { + // FIXME: We could use the inner item to check this is really a + // primitive type but, who the heck overrides these anyway? + Some(match name { + "int8_t" => primitive_ty(ctx, "i8"), + "uint8_t" => primitive_ty(ctx, "u8"), + "int16_t" => primitive_ty(ctx, "i16"), + "uint16_t" => primitive_ty(ctx, "u16"), + "int32_t" => primitive_ty(ctx, "i32"), + "uint32_t" => primitive_ty(ctx, "u32"), + "int64_t" => primitive_ty(ctx, "i64"), + "uint64_t" => primitive_ty(ctx, "u64"), + + "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), + + "intptr_t" | "ptrdiff_t" | "ssize_t" => { + primitive_ty(ctx, "isize") + } + _ => return None, + }) + } + + pub fn rust_fndecl_from_signature(ctx: &BindgenContext, + sig: &Item) + -> P { + let signature = sig.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How?"), + }; + + let decl_ty = signature.try_to_rust_ty(ctx, &()) + .expect("function signature to Rust type conversion is infallible"); + match decl_ty.unwrap().node { + ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, + _ => panic!("How did this happen exactly?"), + } + } + + pub fn fnsig_return_ty(ctx: &BindgenContext, + sig: &FunctionSig) + -> ast::FunctionRetTy { + let return_item = ctx.resolve_item(sig.return_type()); + if let TypeKind::Void = *return_item.kind().expect_type().kind() { + ast::FunctionRetTy::Default(ctx.span()) + } else { + ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) + } + } + + pub fn fnsig_arguments(ctx: &BindgenContext, + sig: &FunctionSig) + -> Vec { + use super::ToPtr; + let mut unnamed_arguments = 0; + sig.argument_types().iter().map(|&(ref name, ty)| { + let arg_item = ctx.resolve_item(ty); + let arg_ty = arg_item.kind().expect_type(); + + // From the C90 standard[1]: + // + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + // + // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html + let arg_ty = match *arg_ty.canonical_type(ctx).kind() { + TypeKind::Array(t, _) => { + t.to_rust_ty_or_opaque(ctx, &()) + .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) + }, + TypeKind::Pointer(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { + quote_ty!(ctx.ext_cx(), id) + } else { + arg_item.to_rust_ty_or_opaque(ctx, &()) + } + }, + _ => { + arg_item.to_rust_ty_or_opaque(ctx, &()) + } + }; + + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + + assert!(!arg_name.is_empty()); + + ast::Arg { + ty: arg_ty, + pat: aster::AstBuilder::new().pat().id(arg_name), + id: ast::DUMMY_NODE_ID, + } + }).collect::>() + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 0000000000..d703e53dbb --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,23 @@ +//! The ir module defines bindgen's intermediate representation. +//! +//! Parsing C/C++ generates the IR, while code generation outputs Rust code from +//! the IR. + +pub mod annotations; +pub mod comp; +pub mod context; +pub mod derive; +pub mod dot; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod named; +pub mod template; +pub mod traversal; +pub mod ty; +pub mod var; +pub mod objc; diff --git a/src/ir/module.rs b/src/ir/module.rs new file mode 100644 index 0000000000..ee3912c5f1 --- /dev/null +++ b/src/ir/module.rs @@ -0,0 +1,91 @@ +//! Intermediate representation for modules (AKA C++ namespaces). + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; +use std::io; + +/// Whether this module is inline or not. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ModuleKind { + /// This module is not inline. + Normal, + /// This module is inline, as in `inline namespace foo {}`. + Inline, +} + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option, + /// The kind of module this is. + kind: ModuleKind, + /// The children of this module, just here for convenience. + children_ids: Vec, +} + +impl Module { + /// Construct a new `Module`. + pub fn new(name: Option, kind: ModuleKind) -> Self { + Module { + name: name, + kind: kind, + children_ids: vec![], + } + } + + /// Get this module's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get a mutable reference to this module's children. + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children_ids + } + + /// Get this module's children. + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } + + /// Whether this namespace is inline. + pub fn is_inline(&self) -> bool { + self.kind == ModuleKind::Inline + } +} + +impl DotAttributes for Module { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + writeln!(out, "ModuleKind{:?}", self.kind) + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx| { + cursor.visit(|cursor| { + parse_one(ctx, cursor, Some(module_id)) + }) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue), + } + } +} diff --git a/src/ir/objc.rs b/src/ir/objc.rs new file mode 100644 index 0000000000..3a88eef8ab --- /dev/null +++ b/src/ir/objc.rs @@ -0,0 +1,254 @@ +//! Objective C types + +use super::context::{BindgenContext, ItemId}; +use super::function::FunctionSig; +use super::traversal::{Trace, Tracer}; +use super::ty::TypeKind; +use clang; +use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCCategoryDecl; +use clang_sys::CXCursor_ObjCClassMethodDecl; +use clang_sys::CXCursor_ObjCClassRef; +use clang_sys::CXCursor_ObjCInstanceMethodDecl; +use clang_sys::CXCursor_ObjCProtocolDecl; +use clang_sys::CXCursor_ObjCProtocolRef; + +/// Objective C interface as used in TypeKind +/// +/// Also protocols and categories are parsed as this type +#[derive(Debug)] +pub struct ObjCInterface { + /// The name + /// like, NSObject + name: String, + + category: Option, + + is_protocol: bool, + + conforms_to: Vec, + + /// List of the methods defined in this interfae + methods: Vec, + + class_methods: Vec, +} + +/// The objective c methods +#[derive(Debug)] +pub struct ObjCMethod { + /// The original method selector name + /// like, dataWithBytes:length: + name: String, + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + rust_name: String, + + signature: FunctionSig, + + /// Is class method? + is_class_method: bool, +} + +impl ObjCInterface { + fn new(name: &str) -> ObjCInterface { + ObjCInterface { + name: name.to_owned(), + category: None, + is_protocol: false, + conforms_to: Vec::new(), + methods: Vec::new(), + class_methods: Vec::new(), + } + } + + /// The name + /// like, NSObject + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + /// and protocols are like protocol_NSObject + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + if self.is_protocol { + format!("protocol_{}", self.name()) + } else { + self.name().to_owned() + } + } + } + + /// List of the methods defined in this interface + pub fn methods(&self) -> &Vec { + &self.methods + } + + /// List of the class methods defined in this interface + pub fn class_methods(&self) -> &Vec { + &self.class_methods + } + + /// Parses the Objective C interface from the cursor + pub fn from_ty(cursor: &clang::Cursor, + ctx: &mut BindgenContext) + -> Option { + let name = cursor.spelling(); + let mut interface = Self::new(&name); + + if cursor.kind() == CXCursor_ObjCProtocolDecl { + interface.is_protocol = true; + } + + cursor.visit(|c| { + match c.kind() { + CXCursor_ObjCClassRef => { + if cursor.kind() == CXCursor_ObjCCategoryDecl { + // We are actually a category extension, and we found the reference + // to the original interface, so name this interface approriately + interface.name = c.spelling(); + interface.category = Some(cursor.spelling()); + } + } + CXCursor_ObjCProtocolRef => { + // Gather protocols this interface conforms to + let needle = format!("protocol_{}", c.spelling()); + let items_map = ctx.items(); + debug!("Interface {} conforms to {}, find the item", interface.name, needle); + + for (id, item) in items_map + { + if let Some(ty) = item.as_type() { + match *ty.kind() { + TypeKind::ObjCInterface(ref protocol) => { + if protocol.is_protocol + { + debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name()); + if Some(needle.as_ref()) == ty.name() + { + debug!("Found conforming protocol {:?}", item); + interface.conforms_to.push(*id); + break; + } + } + } + _ => {} + } + } + } + + } + CXCursor_ObjCInstanceMethodDecl | + CXCursor_ObjCClassMethodDecl => { + let name = c.spelling(); + let signature = + FunctionSig::from_ty(&c.cur_type(), &c, ctx) + .expect("Invalid function sig"); + let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl; + let method = ObjCMethod::new(&name, signature, is_class_method); + interface.add_method(method); + } + _ => {} + } + CXChildVisit_Continue + }); + Some(interface) + } + + fn add_method(&mut self, method: ObjCMethod) { + if method.is_class_method { + self.class_methods.push(method); + } else { + self.methods.push(method); + } + } +} + +impl ObjCMethod { + fn new(name: &str, + signature: FunctionSig, + is_class_method: bool) + -> ObjCMethod { + let split_name: Vec<&str> = name.split(':').collect(); + + let rust_name = split_name.join("_"); + + ObjCMethod { + name: name.to_owned(), + rust_name: rust_name.to_owned(), + signature: signature, + is_class_method: is_class_method, + } + } + + /// The original method selector name + /// like, dataWithBytes:length: + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + pub fn rust_name(&self) -> &str { + self.rust_name.as_ref() + } + + /// Returns the methods signature as FunctionSig + pub fn signature(&self) -> &FunctionSig { + &self.signature + } + + /// Is this a class method? + pub fn is_class_method(&self) -> bool { + self.is_class_method + } + + /// Formats the method call + pub fn format_method_call(&self, args: &[String]) -> String { + let split_name: Vec<&str> = + self.name.split(':').filter(|p| !p.is_empty()).collect(); + + // No arguments + if args.len() == 0 && split_name.len() == 1 { + return split_name[0].to_string(); + } + + // Check right amount of arguments + if args.len() != split_name.len() { + panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}", + args, + split_name); + } + + split_name.iter() + .zip(args.iter()) + .map(|parts| format!("{}:{} ", parts.0, parts.1)) + .collect::>() + .join("") + } +} + +impl Trace for ObjCInterface { + type Extra = (); + + fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) + where T: Tracer, + { + for method in &self.methods { + method.signature.trace(context, tracer, &()); + } + + for class_method in &self.class_methods { + class_method.signature.trace(context, tracer, &()); + } + + for protocol in &self.conforms_to { + tracer.visit(*protocol); + } + } +} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs new file mode 100644 index 0000000000..95d2a45675 --- /dev/null +++ b/src/ir/traversal.rs @@ -0,0 +1,476 @@ +//! Traversal of the graph of IR items and types. + +use super::context::{BindgenContext, ItemId}; +use super::item::ItemSet; +use std::collections::{BTreeMap, VecDeque}; + +/// An outgoing edge in the IR graph is a reference from some item to another +/// item: +/// +/// from --> to +/// +/// The `from` is left implicit: it is the concrete `Trace` implementor which +/// yielded this outgoing edge. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Edge { + to: ItemId, + kind: EdgeKind, +} + +impl Edge { + /// Construct a new edge whose referent is `to` and is of the given `kind`. + pub fn new(to: ItemId, kind: EdgeKind) -> Edge { + Edge { + to: to, + kind: kind, + } + } + + /// Get the item that this edge is pointing to. + pub fn to(&self) -> ItemId { + self.to + } + + /// Get the kind of edge that this is. + pub fn kind(&self) -> EdgeKind { + self.kind + } +} + +impl Into for Edge { + fn into(self) -> ItemId { + self.to + } +} + +/// The kind of edge reference. This is useful when we wish to only consider +/// certain kinds of edges for a particular traversal or analysis. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EdgeKind { + /// A generic, catch-all edge. + Generic, + + /// An edge from a template declaration, to the definition of a named type + /// parameter. For example, the edge from `Foo` to `T` in the following + /// snippet: + /// + /// ```C++ + /// template + /// class Foo { }; + /// ``` + TemplateParameterDefinition, + + /// An edge from a template instantiation to the template declaration that + /// is being instantiated. For example, the edge from `Foo` to + /// to `Foo`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// using Bar = Foo; + /// ``` + TemplateDeclaration, + + /// An edge from a template instantiation to its template argument. For + /// example, `Foo` to `Bar`: + /// + /// ```C++ + /// template + /// class Foo { }; + /// + /// class Bar { }; + /// + /// using FooBar = Foo; + /// ``` + TemplateArgument, + + /// An edge from a compound type to one of its base member types. For + /// example, the edge from `Bar` to `Foo`: + /// + /// ```C++ + /// class Foo { }; + /// + /// class Bar : public Foo { }; + /// ``` + BaseMember, + + /// An edge from a compound type to the types of one of its fields. For + /// example, the edge from `Foo` to `int`: + /// + /// ```C++ + /// class Foo { + /// int x; + /// }; + /// ``` + Field, + + /// An edge from an class or struct type to an inner type member. For + /// example, the edge from `Foo` to `Foo::Bar` here: + /// + /// ```C++ + /// class Foo { + /// struct Bar { }; + /// }; + /// ``` + InnerType, + + /// An edge from an class or struct type to an inner static variable. For + /// example, the edge from `Foo` to `Foo::BAR` here: + /// + /// ```C++ + /// class Foo { + /// static const char* BAR; + /// }; + /// ``` + InnerVar, + + /// An edge from a class or struct type to one of its method functions. For + /// example, the edge from `Foo` to `Foo::bar`: + /// + /// ```C++ + /// class Foo { + /// bool bar(int x, int y); + /// }; + /// ``` + Method, + + /// An edge from a class or struct type to one of its constructor + /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: + /// + /// ```C++ + /// class Foo { + /// int my_x; + /// int my_y; + /// + /// public: + /// Foo(int x, int y); + /// }; + /// ``` + Constructor, + + /// An edge from a function declaration to its return type. For example, the + /// edge from `foo` to `int`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionReturn, + + /// An edge from a function declaration to one of its parameter types. For + /// example, the edge from `foo` to `char*`: + /// + /// ```C++ + /// int foo(char* string); + /// ``` + FunctionParameter, + + /// An edge from a static variable to its type. For example, the edge from + /// `FOO` to `const char*`: + /// + /// ```C++ + /// static const char* FOO; + /// ``` + VarType, + + /// An edge from a non-templated alias or typedef to the referenced type. + TypeReference, +} + +/// A predicate to allow visiting only sub-sets of the whole IR graph by +/// excluding certain edges from being followed by the traversal. +pub trait TraversalPredicate { + /// Should the traversal follow this edge, and visit everything that is + /// reachable through it? + fn should_follow(&self, edge: Edge) -> bool; +} + +impl TraversalPredicate for fn(Edge) -> bool { + fn should_follow(&self, edge: Edge) -> bool { + (*self)(edge) + } +} + +/// A `TraversalPredicate` implementation that follows all edges, and therefore +/// traversals using this predicate will see the whole IR graph reachable from +/// the traversal's roots. +pub fn all_edges(_: Edge) -> bool { + true +} + +/// A `TraversalPredicate` implementation that never follows any edges, and +/// therefore traversals using this predicate will only visit the traversal's +/// roots. +pub fn no_edges(_: Edge) -> bool { + false +} + +/// The storage for the set of items that have been seen (although their +/// outgoing edges might not have been fully traversed yet) in an active +/// traversal. +pub trait TraversalStorage<'ctx, 'gen> { + /// Construct a new instance of this TraversalStorage, for a new traversal. + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self; + + /// Add the given item to the storage. If the item has never been seen + /// before, return `true`. Otherwise, return `false`. + /// + /// The `from` item is the item from which we discovered this item, or is + /// `None` if this item is a root. + fn add(&mut self, from: Option, item: ItemId) -> bool; +} + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for ItemSet { + fn new(_: &'ctx BindgenContext<'gen>) -> Self { + ItemSet::new() + } + + fn add(&mut self, _: Option, item: ItemId) -> bool { + self.insert(item) + } +} + +/// A `TraversalStorage` implementation that keeps track of how we first reached +/// each item. This is useful for providing debug assertions with meaningful +/// diagnostic messages about dangling items. +#[derive(Debug)] +pub struct Paths<'ctx, 'gen>(BTreeMap, + &'ctx BindgenContext<'gen>) + where 'gen: 'ctx; + +impl<'ctx, 'gen> TraversalStorage<'ctx, 'gen> for Paths<'ctx, 'gen> + where 'gen: 'ctx, +{ + fn new(ctx: &'ctx BindgenContext<'gen>) -> Self { + Paths(BTreeMap::new(), ctx) + } + + fn add(&mut self, from: Option, item: ItemId) -> bool { + let newly_discovered = + self.0.insert(item, from.unwrap_or(item)).is_none(); + + if self.1.resolve_item_fallible(item).is_none() { + let mut path = vec![]; + let mut current = item; + loop { + let predecessor = *self.0 + .get(¤t) + .expect("We know we found this item id, so it must have a \ + predecessor"); + if predecessor == current { + break; + } + path.push(predecessor); + current = predecessor; + } + path.reverse(); + panic!("Found reference to dangling id = {:?}\nvia path = {:?}", + item, + path); + } + + newly_discovered + } +} + +/// The queue of seen-but-not-yet-traversed items. +/// +/// Using a FIFO queue with a traversal will yield a breadth-first traversal, +/// while using a LIFO queue will result in a depth-first traversal of the IR +/// graph. +pub trait TraversalQueue: Default { + /// Add a newly discovered item to the queue. + fn push(&mut self, item: ItemId); + + /// Pop the next item to traverse, if any. + fn next(&mut self) -> Option; +} + +impl TraversalQueue for Vec { + fn push(&mut self, item: ItemId) { + self.push(item); + } + + fn next(&mut self) -> Option { + self.pop() + } +} + +impl TraversalQueue for VecDeque { + fn push(&mut self, item: ItemId) { + self.push_back(item); + } + + fn next(&mut self) -> Option { + self.pop_front() + } +} + +/// Something that can receive edges from a `Trace` implementation. +pub trait Tracer { + /// Note an edge between items. Called from within a `Trace` implementation. + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); + + /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. + fn visit(&mut self, item: ItemId) { + self.visit_kind(item, EdgeKind::Generic); + } +} + +impl Tracer for F + where F: FnMut(ItemId, EdgeKind), +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + (*self)(item, kind) + } +} + +/// Trace all of the outgoing edges to other items. Implementations should call +/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` +/// for each of their outgoing edges. +pub trait Trace { + /// If a particular type needs extra information beyond what it has in + /// `self` and `context` to find its referenced items, its implementation + /// can define this associated type, forcing callers to pass the needed + /// information through. + type Extra; + + /// Trace all of this item's outgoing edges to other items. + fn trace(&self, + context: &BindgenContext, + tracer: &mut T, + extra: &Self::Extra) + where T: Tracer; +} + +/// An graph traversal of the transitive closure of references between items. +/// +/// See `BindgenContext::whitelisted_items` for more information. +pub struct ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + ctx: &'ctx BindgenContext<'gen>, + + /// The set of items we have seen thus far in this traversal. + seen: Storage, + + /// The set of items that we have seen, but have yet to traverse. + queue: Queue, + + /// The predicate that determins which edges this traversal will follow. + predicate: Predicate, + + /// The item we are currently traversing. + currently_traversing: Option, +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> ItemTraversal<'ctx, + 'gen, + Storage, + Queue, + Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + /// Begin a new traversal, starting from the given roots. + pub fn new(ctx: &'ctx BindgenContext<'gen>, + roots: R, + predicate: Predicate) + -> ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where R: IntoIterator, + { + let mut seen = Storage::new(ctx); + let mut queue = Queue::default(); + + for id in roots { + seen.add(None, id); + queue.push(id); + } + + ItemTraversal { + ctx: ctx, + seen: seen, + queue: queue, + predicate: predicate, + currently_traversing: None, + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { + let edge = Edge::new(item, kind); + if !self.predicate.should_follow(edge) { + return; + } + + let is_newly_discovered = self.seen + .add(self.currently_traversing, item); + if is_newly_discovered { + self.queue.push(item) + } + } +} + +impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator + for ItemTraversal<'ctx, 'gen, Storage, Queue, Predicate> + where 'gen: 'ctx, + Storage: TraversalStorage<'ctx, 'gen>, + Queue: TraversalQueue, + Predicate: TraversalPredicate, +{ + type Item = ItemId; + + fn next(&mut self) -> Option { + let id = match self.queue.next() { + None => return None, + Some(id) => id, + }; + + let newly_discovered = self.seen.add(None, id); + debug_assert!(!newly_discovered, + "should have already seen anything we get out of our queue"); + debug_assert!(self.ctx.resolve_item_fallible(id).is_some(), + "should only get IDs of actual items in our context during traversal"); + + self.currently_traversing = Some(id); + id.trace(self.ctx, self, &()); + self.currently_traversing = None; + + Some(id) + } +} + +/// An iterator to find any dangling items. +/// +/// See `BindgenContext::assert_no_dangling_item_traversal` for more +/// information. +pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = + ItemTraversal<'ctx, + 'gen, + Paths<'ctx, 'gen>, + VecDeque, + fn(Edge) -> bool>; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(dead_code)] + fn traversal_predicate_is_object_safe() { + // This should compile only if TraversalPredicate is object safe. + fn takes_by_trait_object(_: &TraversalPredicate) {} + } +} diff --git a/src/ir/var.rs b/src/ir/var.rs new file mode 100644 index 0000000000..656a1a6dfd --- /dev/null +++ b/src/ir/var.rs @@ -0,0 +1,342 @@ +//! Intermediate representation of variables. + +use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; +use super::function::cursor_mangling; +use super::int::IntKind; +use super::item::Item; +use super::ty::{FloatKind, TypeKind}; +use cexpr; +use clang; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; +use std::num::Wrapping; + +/// The type for a constant variable. +#[derive(Debug)] +pub enum VarType { + /// A boolean. + Bool(bool), + /// An integer. + Int(i64), + /// A floating point number. + Float(f64), + /// A character. + Char(u8), + /// A string, not necessarily well-formed utf-8. + String(Vec), +} + +/// A `Var` is our intermediate representation of a variable. +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option, + /// The type of the variable. + ty: ItemId, + /// The value of the variable, that needs to be suitable for `ty`. + val: Option, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + /// Construct a new `Var`. + pub fn new(name: String, + mangled: Option, + ty: ItemId, + val: Option, + is_const: bool) + -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + /// Is this variable `const` qualified? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// The value of this constant variable, if any. + pub fn val(&self) -> Option<&VarType> { + self.val.as_ref() + } + + /// Get this variable's type. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get this variable's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variable's mangled name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl DotAttributes for Var { + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, + { + if self.is_const { + try!(writeln!(out, "consttrue")); + } + + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, + "mangled name{}", + mangled)); + } + + Ok(()) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result, ParseError> { + use clang_sys::*; + use cexpr::expr::EvalResult; + use cexpr::literal::CChar; + match cursor.kind() { + CXCursor_MacroDefinition => { + + if let Some(visitor) = ctx.parse_callbacks() { + visitor.parsed_macro(&cursor.spelling()); + } + + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); + + let (id, value) = match value { + Some(v) => v, + None => return Err(ParseError::Continue), + }; + + assert!(!id.is_empty(), "Empty macro name?"); + + let previously_defined = ctx.parsed_macro(&id); + + // NB: It's important to "note" the macro even if the result is + // not an integer, otherwise we might loose other kind of + // derived macros. + ctx.note_parsed_macro(id.clone(), value.clone()); + + if previously_defined { + let name = String::from_utf8(id).unwrap(); + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + + // NOTE: Unwrapping, here and above, is safe, because the + // identifier of a token comes straight from clang, and we + // enforce utf8 there, so we should have already panicked at + // this point. + let name = String::from_utf8(id).unwrap(); + let (type_kind, val) = match value { + EvalResult::Invalid => return Err(ParseError::Continue), + EvalResult::Float(f) => { + (TypeKind::Float(FloatKind::Double), VarType::Float(f)) + } + EvalResult::Char(c) => { + let c = match c { + CChar::Char(c) => { + assert_eq!(c.len_utf8(), 1); + c as u8 + } + CChar::Raw(c) => { + assert!(c <= ::std::u8::MAX as u64); + c as u8 + } + }; + + (TypeKind::Int(IntKind::U8), VarType::Char(c)) + } + EvalResult::Str(val) => { + let char_ty = + Item::builtin_type(TypeKind::Int(IntKind::U8), + true, + ctx); + (TypeKind::Pointer(char_ty), VarType::String(val)) + } + EvalResult::Int(Wrapping(value)) => { + let kind = ctx.parse_callbacks() + .and_then(|c| c.int_macro(&name, value)) + .unwrap_or_else(|| if value < 0 { + if value < i32::min_value() as i64 { + IntKind::LongLong + } else { + IntKind::Int + } + } else if value > u32::max_value() as i64 { + IntKind::ULongLong + } else { + IntKind::UInt + }); + + (TypeKind::Int(kind), VarType::Int(value)) + } + }; + + let ty = Item::builtin_type(type_kind, true, ctx); + + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), + Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = match Item::from_ty(&ty, cursor, None, ctx) { + Ok(ty) => ty, + Err(e) => { + assert_eq!(ty.kind(), + CXType_Auto, + "Couldn't resolve constant type, and it \ + wasn't an nondeductible auto type!"); + return Err(e); + } + }; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + let canonical_ty = ctx.safe_resolve_type(ty) + .and_then(|t| t.safe_canonical_type(ctx)); + + let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); + let is_float = canonical_ty.map_or(false, |t| t.is_float()); + + // TODO: We could handle `char` more gracefully. + // TODO: Strings, though the lookup is a bit more hard (we need + // to look at the canonical type of the pointee too, and check + // is char, u8, or i8 I guess). + let value = if is_integer { + let kind = match *canonical_ty.unwrap().kind() { + TypeKind::Int(kind) => kind, + _ => unreachable!(), + }; + + let mut val = cursor.evaluate() + .and_then(|v| v.as_int()) + .map(|val| val as i64); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { + let tu = ctx.translation_unit(); + val = get_integer_literal_from_cursor(&cursor, tu); + } + + val.map(|val| if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + }) + } else if is_float { + cursor.evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float) + } else { + cursor.evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String) + }; + + let mangling = cursor_mangling(ctx, &cursor); + let var = Var::new(name, mangling, ty, value, is_const); + + Ok(ParseResult::New(var, Some(cursor))) + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +/// Try and parse a macro using all the macros parsed until now. +fn parse_macro(ctx: &BindgenContext, + cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<(Vec, cexpr::expr::EvalResult)> { + use cexpr::{expr, nom}; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); + let result = parser.macro_definition(&cexpr_tokens); + + match result { + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), + _ => None, + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use cexpr::{expr, nom}; + use cexpr::expr::EvalResult; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + // TODO(emilio): We can try to parse other kinds of literals. + match expr::expr(&cexpr_tokens) { + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), + _ => None, + } +} + +fn get_integer_literal_from_cursor(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option { + use clang_sys::*; + let mut value = None; + cursor.visit(|c| { + match c.kind() { + CXCursor_IntegerLiteral | + CXCursor_UnaryOperator => { + value = parse_int_literal_tokens(&c, unit); + } + CXCursor_UnexposedExpr => { + value = get_integer_literal_from_cursor(&c, unit); + } + _ => (), + } + if value.is_some() { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + value +} diff --git a/src/main.rs b/src/main.rs index 5338f574fc..2ba2b1394a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,12 +22,12 @@ use options::builder_from_flags; pub fn main() { #[cfg(feature="logging")] log::set_logger(|max_log_level| { - use env_logger::Logger; - let env_logger = Logger::new(); - max_log_level.set(env_logger.filter()); - Box::new(env_logger) - }) - .expect("Failed to set logger."); + use env_logger::Logger; + let env_logger = Logger::new(); + max_log_level.set(env_logger.filter()); + Box::new(env_logger) + }) + .expect("Failed to set logger."); let bind_args: Vec<_> = env::args().collect(); @@ -52,8 +52,8 @@ pub fn main() { Ok((builder, output, verbose)) => { let builder_result = panic::catch_unwind(|| { - builder.generate().expect("Unable to generate bindings") - }); + builder.generate().expect("Unable to generate bindings") + }); if builder_result.is_err() { if verbose { @@ -63,9 +63,9 @@ pub fn main() { } let mut bindings = builder_result.unwrap(); - bindings.write(output).expect("Unable to write output"); - bindings - .write_dummy_uses() + bindings.write(output) + .expect("Unable to write output"); + bindings.write_dummy_uses() .expect("Unable to write dummy uses to file."); } Err(error) => { diff --git a/src/options.rs b/src/options.rs index 4948d0fdcf..9072abd820 100644 --- a/src/options.rs +++ b/src/options.rs @@ -7,7 +7,7 @@ use std::io::{self, Error, ErrorKind}; pub fn builder_from_flags (args: I) -> Result<(Builder, Box, bool), io::Error> - where I: Iterator + where I: Iterator, { let matches = App::new("bindgen") .version(env!("CARGO_PKG_VERSION")) diff --git a/tests/expectations/tests/anonymous-template-types.rs b/tests/expectations/tests/anonymous-template-types.rs index 50604a3f1b..d5e712dd15 100644 --- a/tests/expectations/tests/anonymous-template-types.rs +++ b/tests/expectations/tests/anonymous-template-types.rs @@ -1,35 +1,35 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t_member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Bar { - pub member: ::std::os::raw::c_char, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Quux { - pub v_member: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Quux { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Lobo { - pub also_member: ::std::os::raw::c_char, -} -pub type AliasWithAnonType = ::std::os::raw::c_char; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t_member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Bar { + pub member: ::std::os::raw::c_char, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Quux { + pub v_member: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Quux { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Lobo { + pub also_member: ::std::os::raw::c_char, +} +pub type AliasWithAnonType = ::std::os::raw::c_char; diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index 8446cbcdf6..60f8633625 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -1,132 +1,132 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub member_a: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_B { - pub member_b: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_B() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_B ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_B ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_B ) , "::" , - stringify ! ( member_b ) )); -} -impl Clone for A_B { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_C { - pub baz: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_C() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_C ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_C ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_C ) , "::" , - stringify ! ( baz ) )); -} -impl Clone for A_C { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct A_D { - pub foo: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for A_D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , stringify - ! ( member_a ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -extern "C" { - #[link_name = "var"] - pub static mut var: A_B; -} -#[test] -fn __bindgen_test_layout_A_D_instantiation_16() { - assert_eq!(::std::mem::size_of::>() , 4usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 4usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); -} -extern "C" { - #[link_name = "baz"] - pub static mut baz: A_D<::std::os::raw::c_int>; -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct D { - pub member: A_B, -} -#[test] -fn bindgen_test_layout_D() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( D ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( D ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const D ) ) . member as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( D ) , "::" , stringify - ! ( member ) )); -} -impl Clone for D { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated_Templated_inner { - pub member_ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Templated_Templated_inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for Templated { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub member_a: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_B { + pub member_b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_B() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_B ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_B ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_B ) , "::" , + stringify ! ( member_b ) )); +} +impl Clone for A_B { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_C { + pub baz: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_C() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_C ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_C ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_C ) , "::" , + stringify ! ( baz ) )); +} +impl Clone for A_C { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct A_D { + pub foo: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for A_D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , stringify + ! ( member_a ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +extern "C" { + #[link_name = "var"] + pub static mut var: A_B; +} +#[test] +fn __bindgen_test_layout_A_D_instantiation_16() { + assert_eq!(::std::mem::size_of::>() , 4usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 4usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); +} +extern "C" { + #[link_name = "baz"] + pub static mut baz: A_D<::std::os::raw::c_int>; +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct D { + pub member: A_B, +} +#[test] +fn bindgen_test_layout_D() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( D ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( D ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const D ) ) . member as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( D ) , "::" , stringify + ! ( member ) )); +} +impl Clone for D { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated_Templated_inner { + pub member_ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Templated_Templated_inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for Templated { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 3b15b89138..60464cc2a6 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -1,47 +1,47 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct HandleWithDtor { - pub ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for HandleWithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct WithoutDtor { - pub shouldBeWithDtor: HandleValue, -} -#[test] -fn bindgen_test_layout_WithoutDtor() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( WithoutDtor ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( WithoutDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , - stringify ! ( shouldBeWithDtor ) )); -} -impl Default for WithoutDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { - assert_eq!(::std::mem::size_of::>() - , 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() - , 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct HandleWithDtor { + pub ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for HandleWithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct WithoutDtor { + pub shouldBeWithDtor: HandleValue, +} +#[test] +fn bindgen_test_layout_WithoutDtor() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( WithoutDtor ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( WithoutDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , + stringify ! ( shouldBeWithDtor ) )); +} +impl Default for WithoutDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { + assert_eq!(::std::mem::size_of::>() + , 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() + , 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/const_tparam.rs b/tests/expectations/tests/const_tparam.rs index 7600e18eed..aaa89f9c92 100644 --- a/tests/expectations/tests/const_tparam.rs +++ b/tests/expectations/tests/const_tparam.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct C { - pub foo: *const T, - pub bar: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct C { + pub foo: *const T, + pub bar: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/default-template-parameter.rs b/tests/expectations/tests/default-template-parameter.rs index af4616ff9b..70207694a1 100644 --- a/tests/expectations/tests/default-template-parameter.rs +++ b/tests/expectations/tests/default-template-parameter.rs @@ -1,30 +1,32 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t: T, - pub u: U, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_6() { - assert_eq!(::std::mem::size_of::>() , - 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Foo ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo ) )); -} -extern "C" { - #[link_name = "_ZL3bar"] - pub static mut bar: Foo; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t: T, + pub u: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_6() { + assert_eq!(::std::mem::size_of::>() , + 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Foo ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo ) )); +} +extern "C" { + #[link_name = "_ZL3bar"] + pub static mut bar: Foo; +} diff --git a/tests/expectations/tests/forward-declaration-autoptr.rs b/tests/expectations/tests/forward-declaration-autoptr.rs index 3b5e261618..acd5b535f2 100644 --- a/tests/expectations/tests/forward-declaration-autoptr.rs +++ b/tests/expectations/tests/forward-declaration-autoptr.rs @@ -1,41 +1,41 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo([u8; 0]); -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr { - pub m_inner: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for RefPtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct Bar { - pub m_member: RefPtr, -} -#[test] -fn bindgen_test_layout_Bar() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( Bar ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( Bar ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( Bar ) , "::" , - stringify ! ( m_member ) )); -} -impl Clone for Bar { - fn clone(&self) -> Self { *self } -} -impl Default for Bar { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo([u8; 0]); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr { + pub m_inner: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for RefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Bar { + pub m_member: RefPtr, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( Bar ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( Bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Bar ) , "::" , + stringify ! ( m_member ) )); +} +impl Clone for Bar { + fn clone(&self) -> Self { *self } +} +impl Default for Bar { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/forward-inherit-struct-with-fields.rs b/tests/expectations/tests/forward-inherit-struct-with-fields.rs index 1b31f62b57..4a61631995 100644 --- a/tests/expectations/tests/forward-inherit-struct-with-fields.rs +++ b/tests/expectations/tests/forward-inherit-struct-with-fields.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub _base: js_RootedBase, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct js_RootedBase { - pub foo: *mut T, - pub next: *mut Rooted, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for js_RootedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub _base: js_RootedBase, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct js_RootedBase { + pub foo: *mut T, + pub next: *mut Rooted, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for js_RootedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index a641de70b5..e67a55a76d 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wohoo { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Weeee { - pub _base: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Weeee { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wohoo { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Weeee { + pub _base: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Weeee { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs index 91b8e49a16..e83d5800b5 100644 --- a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs +++ b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs @@ -1,80 +1,81 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - -pub type RefPtr = T; - -#[repr(C)] -#[derive(Debug, Copy)] -pub struct b { - pub _base: g, -} -#[test] -fn bindgen_test_layout_b() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( b ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( b ) )); -} -impl Clone for b { - fn clone(&self) -> Self { *self } -} -impl Default for b { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub _address: u8, -} -pub type A_a = b; -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct e { - pub d: RefPtr, -} -impl Default for e { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct f { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct g { - pub h: f, -} -#[test] -fn bindgen_test_layout_g() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( g ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( g ) )); - assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( g ) , "::" , stringify - ! ( h ) )); -} -impl Clone for g { - fn clone(&self) -> Self { *self } -} -impl Default for g { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z25Servo_Element_GetSnapshotv"] - pub fn Servo_Element_GetSnapshot() -> A; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +pub type RefPtr = T; + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct b { + pub _base: g, +} +#[test] +fn bindgen_test_layout_b() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( b ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( b ) )); +} +impl Clone for b { + fn clone(&self) -> Self { *self } +} +impl Default for b { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub _address: u8, +} +pub type A_a = b; +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct e { + pub d: RefPtr, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for e { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct f { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct g { + pub h: f, +} +#[test] +fn bindgen_test_layout_g() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( g ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( g ) )); + assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( g ) , "::" , stringify + ! ( h ) )); +} +impl Clone for g { + fn clone(&self) -> Self { *self } +} +impl Default for g { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z25Servo_Element_GetSnapshotv"] + pub fn Servo_Element_GetSnapshot() -> A; +} diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs index 86d5e89247..7520f03d8d 100644 --- a/tests/expectations/tests/namespace.rs +++ b/tests/expectations/tests/namespace.rs @@ -1,103 +1,103 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - extern "C" { - #[link_name = "_Z9top_levelv"] - pub fn top_level(); - } - pub mod whatever { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_int; - extern "C" { - #[link_name = "_ZN8whatever11in_whateverEv"] - pub fn in_whatever(); - } - } - pub mod _bindgen_mod_id_13 { - #[allow(unused_imports)] - use self::super::super::root; - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_13fooEv"] - pub fn foo(); - } - #[repr(C)] - #[derive(Debug, Default, Copy)] - pub struct A { - pub b: root::whatever::whatever_int_t, - } - #[test] - fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . b as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , - stringify ! ( b ) )); - } - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] - pub fn A_lets_hope_this_works(this: - *mut root::_bindgen_mod_id_13::A) - -> ::std::os::raw::c_int; - } - impl Clone for A { - fn clone(&self) -> Self { *self } - } - impl A { - #[inline] - pub unsafe fn lets_hope_this_works(&mut self) - -> ::std::os::raw::c_int { - A_lets_hope_this_works(self) - } - } - } - #[repr(C)] - #[derive(Debug)] - pub struct C { - pub _base: root::_bindgen_mod_id_13::A, - pub m_c: T, - pub m_c_ptr: *mut T, - pub m_c_arr: [T; 10usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - pub mod w { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_uint; - #[repr(C)] - #[derive(Debug)] - pub struct D { - pub m_c: root::C, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - extern "C" { - #[link_name = "_ZN1w3hehEv"] - pub fn heh() -> root::w::whatever_int_t; - } - extern "C" { - #[link_name = "_ZN1w3fooEv"] - pub fn foo() -> root::C<::std::os::raw::c_int>; - } - extern "C" { - #[link_name = "_ZN1w4barrEv"] - pub fn barr() -> root::C; - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + extern "C" { + #[link_name = "_Z9top_levelv"] + pub fn top_level(); + } + pub mod whatever { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_int; + extern "C" { + #[link_name = "_ZN8whatever11in_whateverEv"] + pub fn in_whatever(); + } + } + pub mod _bindgen_mod_id_13 { + #[allow(unused_imports)] + use self::super::super::root; + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_13fooEv"] + pub fn foo(); + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct A { + pub b: root::whatever::whatever_int_t, + } + #[test] + fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . b as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , + stringify ! ( b ) )); + } + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] + pub fn A_lets_hope_this_works(this: + *mut root::_bindgen_mod_id_13::A) + -> ::std::os::raw::c_int; + } + impl Clone for A { + fn clone(&self) -> Self { *self } + } + impl A { + #[inline] + pub unsafe fn lets_hope_this_works(&mut self) + -> ::std::os::raw::c_int { + A_lets_hope_this_works(self) + } + } + } + #[repr(C)] + #[derive(Debug)] + pub struct C { + pub _base: root::_bindgen_mod_id_13::A, + pub m_c: T, + pub m_c_ptr: *mut T, + pub m_c_arr: [T; 10usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + pub mod w { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug)] + pub struct D { + pub m_c: root::C, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + extern "C" { + #[link_name = "_ZN1w3hehEv"] + pub fn heh() -> root::w::whatever_int_t; + } + extern "C" { + #[link_name = "_ZN1w3fooEv"] + pub fn foo() -> root::C<::std::os::raw::c_int>; + } + extern "C" { + #[link_name = "_ZN1w4barrEv"] + pub fn barr() -> root::C; + } + } +} diff --git a/tests/expectations/tests/nsStyleAutoArray.rs b/tests/expectations/tests/nsStyleAutoArray.rs index 04f01c0c3d..239dfbdd2b 100644 --- a/tests/expectations/tests/nsStyleAutoArray.rs +++ b/tests/expectations/tests/nsStyleAutoArray.rs @@ -1,30 +1,30 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsTArray { - pub mBuff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for nsTArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsStyleAutoArray { - pub mFirstElement: T, - pub mOtherElements: nsTArray, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum nsStyleAutoArray_WithSingleInitialElement { - WITH_SINGLE_INITIAL_ELEMENT = 0, -} -impl Default for nsStyleAutoArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsTArray { + pub mBuff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsTArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsStyleAutoArray { + pub mFirstElement: T, + pub mOtherElements: nsTArray, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum nsStyleAutoArray_WithSingleInitialElement { + WITH_SINGLE_INITIAL_ELEMENT = 0, +} +impl Default for nsStyleAutoArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replace_template_alias.rs b/tests/expectations/tests/replace_template_alias.rs index 65a5332b9a..efe507157b 100644 --- a/tests/expectations/tests/replace_template_alias.rs +++ b/tests/expectations/tests/replace_template_alias.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -/// But the replacement type does use T! -/// -///
-pub type JS_detail_MaybeWrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +/// But the replacement type does use T! +/// +///
+pub type JS_detail_MaybeWrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replaces_double.rs b/tests/expectations/tests/replaces_double.rs index f7093d3d65..4177889385 100644 --- a/tests/expectations/tests/replaces_double.rs +++ b/tests/expectations/tests/replaces_double.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: Rooted_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -/** - *
- */ -pub type Rooted_MaybeWrapped = T; -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: Rooted_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +/** + *
+ */ +pub type Rooted_MaybeWrapped = T; +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs index a36d729a4e..a30d52f9f0 100644 --- a/tests/expectations/tests/template-param-usage-0.rs +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -1,15 +1,15 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs index d41740cd7a..0bfd6ad6e0 100644 --- a/tests/expectations/tests/template-param-usage-10.rs +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage { - pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type DoublyIndirectUsage_Aliased = T; -pub type DoublyIndirectUsage_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage_IndirectUsage { - pub member: DoublyIndirectUsage_Aliased, - pub another: DoublyIndirectUsage_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoublyIndirectUsage_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for DoublyIndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage { + pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type DoublyIndirectUsage_Aliased = T; +pub type DoublyIndirectUsage_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage_IndirectUsage { + pub member: DoublyIndirectUsage_Aliased, + pub another: DoublyIndirectUsage_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoublyIndirectUsage_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for DoublyIndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs index fcf10615f0..c3494b4fc6 100644 --- a/tests/expectations/tests/template-param-usage-12.rs +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub t: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseUsesT>, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub t: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseUsesT>, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs index 10e45ed1f0..d4b52494e9 100644 --- a/tests/expectations/tests/template-param-usage-13.rs +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct BaseIgnoresT { - pub x: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseIgnoresT, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BaseIgnoresT { + pub x: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseIgnoresT, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs index 77667b454f..db48fa3be8 100644 --- a/tests/expectations/tests/template-param-usage-15.rs +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub usage: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpIgnoresU { - pub _base: BaseUsesT, - pub y: ::std::os::raw::c_int, -} -impl Default for CrtpIgnoresU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub usage: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpIgnoresU { + pub _base: BaseUsesT, + pub y: ::std::os::raw::c_int, +} +impl Default for CrtpIgnoresU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs index 4f5987a105..a9ac824b71 100644 --- a/tests/expectations/tests/template-param-usage-2.rs +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { - pub also: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { + pub also: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs index 07571dcc45..c5f40e3842 100644 --- a/tests/expectations/tests/template-param-usage-3.rs +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -1,27 +1,27 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - pub also: T, - pub more: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for - UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + pub also: T, + pub more: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for + UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs index 7b8fe9f1ec..dd6886645c 100644 --- a/tests/expectations/tests/template-param-usage-4.rs +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { - pub x: ::std::os::raw::c_int, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { + pub x: ::std::os::raw::c_int, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs index 3efdfac339..599208d0c3 100644 --- a/tests/expectations/tests/template-param-usage-5.rs +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectlyUsesTemplateParameter { - pub aliased: IndirectlyUsesTemplateParameter_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectlyUsesTemplateParameter_Aliased = T; -impl Default for IndirectlyUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectlyUsesTemplateParameter { + pub aliased: IndirectlyUsesTemplateParameter_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectlyUsesTemplateParameter_Aliased = T; +impl Default for IndirectlyUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs index 3d1378ad98..5f55400cee 100644 --- a/tests/expectations/tests/template-param-usage-7.rs +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUseU { - pub t: T, - pub v: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUseU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUseU { + pub t: T, + pub v: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUseU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs index 322c725718..ee81e2b7bf 100644 --- a/tests/expectations/tests/template-param-usage-8.rs +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectUsage { - pub member1: IndirectUsage_Typedefed, - pub member2: IndirectUsage_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectUsage_Typedefed = T; -pub type IndirectUsage_Aliased = U; -impl Default for IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectUsage { + pub member1: IndirectUsage_Typedefed, + pub member2: IndirectUsage_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectUsage_Typedefed = T; +pub type IndirectUsage_Aliased = U; +impl Default for IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs index 5f2319c448..02a6bd469e 100644 --- a/tests/expectations/tests/template-param-usage-9.rs +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct DoesNotUse { - pub _address: u8, -} -pub type DoesNotUse_Aliased = T; -pub type DoesNotUse_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUse_IndirectUsage { - pub member: DoesNotUse_Aliased, - pub another: DoesNotUse_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUse_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUse { + pub _address: u8, +} +pub type DoesNotUse_Aliased = T; +pub type DoesNotUse_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUse_IndirectUsage { + pub member: DoesNotUse_Aliased, + pub another: DoesNotUse_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUse_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 682c6db9c1..cbabaa99ff 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -1,279 +1,279 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct Foo { - pub m_member: T, - pub m_member_ptr: *mut T, - pub m_member_arr: [T; 1usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z3bar3FooIiiE"] - pub fn bar(foo: Foo<::std::os::raw::c_int>); -} -#[repr(C)] -#[derive(Debug)] -pub struct D { - pub m_foo: D_MyFoo, -} -pub type D_MyFoo = Foo<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct D_U { - pub m_nested_foo: D_MyFoo, - pub m_baz: Z, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for D_U { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub prev: *mut T, - pub next: *mut Rooted<*mut ::std::os::raw::c_void>, - pub ptr: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct RootedContainer { - pub root: Rooted<*mut ::std::os::raw::c_void>, -} -#[test] -fn bindgen_test_layout_RootedContainer() { - assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( - "Size of: " , stringify ! ( RootedContainer ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! - ( "Alignment of " , stringify ! ( RootedContainer ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const RootedContainer ) ) . root as * const _ - as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( RootedContainer ) , - "::" , stringify ! ( root ) )); -} -impl Clone for RootedContainer { - fn clone(&self) -> Self { *self } -} -impl Default for RootedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct WithDtor { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct PODButContainsDtor { - pub member: WithDtorIntFwd, -} -#[test] -fn bindgen_test_layout_PODButContainsDtor() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! - ( "Size of: " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat - ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const PODButContainsDtor ) ) . member as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( PODButContainsDtor ) , - "::" , stringify ! ( member ) )); -} -impl Default for PODButContainsDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/**
*/ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Opaque { -} -impl Default for Opaque { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct POD { - pub opaque_member: u32, -} -#[test] -fn bindgen_test_layout_POD() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( POD ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( POD ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( POD ) , "::" , - stringify ! ( opaque_member ) )); -} -impl Clone for POD { - fn clone(&self) -> Self { *self } -} -/** - *
- */ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedReplaced { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedReplaced { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedBase { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Incomplete { - pub d: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Incomplete { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedContainer { - pub c: T, - pub nested: NestedReplaced, - pub inc: Incomplete, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct Untemplated { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_Untemplated() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( Untemplated ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( Untemplated ) )); -} -impl Clone for Untemplated { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Templated { - pub m_untemplated: Untemplated, -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructor { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiable { - pub m_member: ReplacedWithoutDestructor, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiable { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiableAsWell { - pub m_member: ReplacedWithoutDestructorFwd, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiableAsWell { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructorFwd { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructorFwd { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct TemplateWithVar { - pub _address: u8, -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_95() { - assert_eq!(::std::mem::size_of::>() , 24usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 8usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); -} -#[test] -fn __bindgen_test_layout_Rooted_instantiation_106() { - assert_eq!(::std::mem::size_of::>() , - 24usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); - assert_eq!(::std::mem::align_of::>() , - 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); -} -#[test] -fn __bindgen_test_layout_WithDtor_instantiation_114() { - assert_eq!(::std::mem::size_of::>() , - 4usize , concat ! ( - "Size of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct Foo { + pub m_member: T, + pub m_member_ptr: *mut T, + pub m_member_arr: [T; 1usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z3bar3FooIiiE"] + pub fn bar(foo: Foo<::std::os::raw::c_int>); +} +#[repr(C)] +#[derive(Debug)] +pub struct D { + pub m_foo: D_MyFoo, +} +pub type D_MyFoo = Foo<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct D_U { + pub m_nested_foo: D_MyFoo, + pub m_baz: Z, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for D_U { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub prev: *mut T, + pub next: *mut Rooted<*mut ::std::os::raw::c_void>, + pub ptr: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct RootedContainer { + pub root: Rooted<*mut ::std::os::raw::c_void>, +} +#[test] +fn bindgen_test_layout_RootedContainer() { + assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( + "Size of: " , stringify ! ( RootedContainer ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! + ( "Alignment of " , stringify ! ( RootedContainer ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const RootedContainer ) ) . root as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( RootedContainer ) , + "::" , stringify ! ( root ) )); +} +impl Clone for RootedContainer { + fn clone(&self) -> Self { *self } +} +impl Default for RootedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct WithDtor { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct PODButContainsDtor { + pub member: WithDtorIntFwd, +} +#[test] +fn bindgen_test_layout_PODButContainsDtor() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! + ( "Size of: " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat + ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const PODButContainsDtor ) ) . member as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( PODButContainsDtor ) , + "::" , stringify ! ( member ) )); +} +impl Default for PODButContainsDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/**
*/ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Opaque { +} +impl Default for Opaque { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct POD { + pub opaque_member: u32, +} +#[test] +fn bindgen_test_layout_POD() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( POD ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( POD ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as + usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( POD ) , "::" , + stringify ! ( opaque_member ) )); +} +impl Clone for POD { + fn clone(&self) -> Self { *self } +} +/** + *
+ */ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedReplaced { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedReplaced { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedBase { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Incomplete { + pub d: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Incomplete { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedContainer { + pub c: T, + pub nested: NestedReplaced, + pub inc: Incomplete, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Untemplated { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Untemplated() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( Untemplated ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Untemplated ) )); +} +impl Clone for Untemplated { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Templated { + pub m_untemplated: Untemplated, +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructor { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiable { + pub m_member: ReplacedWithoutDestructor, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiable { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiableAsWell { + pub m_member: ReplacedWithoutDestructorFwd, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiableAsWell { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructorFwd { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructorFwd { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct TemplateWithVar { + pub _address: u8, +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_95() { + assert_eq!(::std::mem::size_of::>() , 24usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 8usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); +} +#[test] +fn __bindgen_test_layout_Rooted_instantiation_106() { + assert_eq!(::std::mem::size_of::>() , + 24usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); + assert_eq!(::std::mem::align_of::>() , + 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); +} +#[test] +fn __bindgen_test_layout_WithDtor_instantiation_114() { + assert_eq!(::std::mem::size_of::>() , + 4usize , concat ! ( + "Size of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/template_alias.rs b/tests/expectations/tests/template_alias.rs index f98d165df8..d0943e94e7 100644 --- a/tests/expectations/tests/template_alias.rs +++ b/tests/expectations/tests/template_alias.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type JS_detail_Wrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type JS_detail_Wrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template_alias_namespace.rs b/tests/expectations/tests/template_alias_namespace.rs index 491bb68cad..ff6a8dc0d2 100644 --- a/tests/expectations/tests/template_alias_namespace.rs +++ b/tests/expectations/tests/template_alias_namespace.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - pub mod JS { - #[allow(unused_imports)] - use self::super::super::root; - pub mod detail { - #[allow(unused_imports)] - use self::super::super::super::root; - pub type Wrapped = T; - } - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct Rooted { - pub ptr: root::JS::detail::Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod JS { + #[allow(unused_imports)] + use self::super::super::root; + pub mod detail { + #[allow(unused_imports)] + use self::super::super::super::root; + pub type Wrapped = T; + } + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct Rooted { + pub ptr: root::JS::detail::Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + } +} diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index 5f6b4c38db..f98100314a 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wrapper { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Wrapper_Wrapped { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Wrapper_Wrapped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Wrapper_Type = Wrapper_Wrapped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wrapper { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Wrapper_Wrapped { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Wrapper_Wrapped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Wrapper_Type = Wrapper_Wrapped; diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs index 09c3248621..4f0c2dc8f7 100644 --- a/tests/expectations/tests/type_alias_partial_template_especialization.rs +++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type MaybeWrapped
= A; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type MaybeWrapped = A; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/using.rs b/tests/expectations/tests/using.rs index 44376b93a9..58a981bcff 100644 --- a/tests/expectations/tests/using.rs +++ b/tests/expectations/tests/using.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Point { - pub x: T, - pub y: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Point { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint2D = Point<::std::os::raw::c_int>; -pub type IntVec2D = Point<::std::os::raw::c_int>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Point { + pub x: T, + pub y: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Point { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint2D = Point<::std::os::raw::c_int>; +pub type IntVec2D = Point<::std::os::raw::c_int>; diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index fa56f04b6d..f96c4b9254 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -1,33 +1,33 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct UnknownUnits { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_UnknownUnits() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( UnknownUnits ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( UnknownUnits ) )); -} -impl Clone for UnknownUnits { - fn clone(&self) -> Self { *self } -} -pub type Float = f32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PointTyped { - pub x: F, - pub y: F, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for PointTyped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint = PointTyped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct UnknownUnits { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_UnknownUnits() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( UnknownUnits ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( UnknownUnits ) )); +} +impl Clone for UnknownUnits { + fn clone(&self) -> Self { *self } +} +pub type Float = f32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PointTyped { + pub x: F, + pub y: F, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for PointTyped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint = PointTyped; diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index a83f02735b..6d4377de4a 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe { - pub foo: ::std::os::raw::c_int, - pub bar: WhitelistMe_Inner, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe_Inner { - pub bar: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WhitelistMe_Inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for WhitelistMe { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe { + pub foo: ::std::os::raw::c_int, + pub bar: WhitelistMe_Inner, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe_Inner { + pub bar: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WhitelistMe_Inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for WhitelistMe { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/stylo_sanity.rs b/tests/stylo_sanity.rs index e5bfd1c219..c75d65a4c2 100755 --- a/tests/stylo_sanity.rs +++ b/tests/stylo_sanity.rs @@ -1,548 +1,548 @@ -extern crate bindgen; - -/// A sanity test that we can generate bindings for Stylo. -/// -/// We don't assert on expected output because its just too big. The output will -/// change too often, and it won't be clear what is going on at a glance, unlike -/// the other tests with smaller input headers. -/// -/// This test is relatively slow, so we also only run it in release mode. -/// -/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing -/// how long bindings generation takes for Stylo. Stylo bindings generation -/// takes too long to be a proper `#[bench]`. -#[test] -#[cfg(not(any(debug_assertions, - feature = "testing_only_extra_assertions", - feature = "testing_only_llvm_stable")))] -fn sanity_check_can_generate_stylo_bindings() { - use std::time::Instant; - - let then = Instant::now(); - - bindgen::builder() - .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) - .whitelisted_function("Servo_.*") - .whitelisted_function("Gecko_.*") - .hide_type("nsACString_internal") - .hide_type("nsAString_internal") - .hide_type("mozilla::css::URLValue") - .hide_type("RawGeckoAnimationPropertySegment") - .hide_type("RawGeckoComputedTiming") - .hide_type("RawGeckoDocument") - .hide_type("RawGeckoElement") - .hide_type("RawGeckoKeyframeList") - .hide_type("RawGeckoComputedKeyframeValuesList") - .hide_type("RawGeckoFontFaceRuleList") - .hide_type("RawGeckoNode") - .hide_type("RawGeckoAnimationValueList") - .hide_type("RawServoAnimationValue") - .hide_type("RawServoAnimationValueMap") - .hide_type("RawServoDeclarationBlock") - .hide_type("RawGeckoPresContext") - .hide_type("RawGeckoPresContextOwned") - .hide_type("RawGeckoStyleAnimationList") - .hide_type("RawGeckoURLExtraData") - .hide_type("RefPtr") - .hide_type("CSSPseudoClassType") - .hide_type("TraversalRootBehavior") - .hide_type("ComputedTimingFunction_BeforeFlag") - .hide_type("FontFamilyList") - .hide_type("FontFamilyType") - .hide_type("Keyframe") - .hide_type("ServoBundledURI") - .hide_type("ServoElementSnapshot") - .hide_type("SheetParsingMode") - .hide_type("StyleBasicShape") - .hide_type("StyleBasicShapeType") - .hide_type("StyleShapeSource") - .hide_type("nsCSSFontFaceRule") - .hide_type("nsCSSKeyword") - .hide_type("nsCSSPropertyID") - .hide_type("nsCSSShadowArray") - .hide_type("nsCSSUnit") - .hide_type("nsCSSValue") - .hide_type("nsCSSValueSharedList") - .hide_type("nsChangeHint") - .hide_type("nsCursorImage") - .hide_type("nsFont") - .hide_type("nsIAtom") - .hide_type("nsMediaFeature") - .hide_type("nsRestyleHint") - .hide_type("nsStyleBackground") - .hide_type("nsStyleBorder") - .hide_type("nsStyleColor") - .hide_type("nsStyleColumn") - .hide_type("nsStyleContent") - .hide_type("nsStyleContentData") - .hide_type("nsStyleContentType") - .hide_type("nsStyleContext") - .hide_type("nsStyleCoord") - .hide_type("nsStyleCoord_Calc") - .hide_type("nsStyleCoord_CalcValue") - .hide_type("nsStyleDisplay") - .hide_type("nsStyleEffects") - .hide_type("nsStyleFilter") - .hide_type("nsStyleFont") - .hide_type("nsStyleGradient") - .hide_type("nsStyleGradientStop") - .hide_type("nsStyleImage") - .hide_type("nsStyleImageLayers") - .hide_type("nsStyleImageLayers_Layer") - .hide_type("nsStyleImageLayers_LayerType") - .hide_type("nsStyleImageRequest") - .hide_type("nsStyleList") - .hide_type("nsStyleMargin") - .hide_type("nsStyleOutline") - .hide_type("nsStylePadding") - .hide_type("nsStylePosition") - .hide_type("nsStyleQuoteValues") - .hide_type("nsStyleSVG") - .hide_type("nsStyleSVGPaint") - .hide_type("nsStyleSVGReset") - .hide_type("nsStyleTable") - .hide_type("nsStyleTableBorder") - .hide_type("nsStyleText") - .hide_type("nsStyleTextReset") - .hide_type("nsStyleUIReset") - .hide_type("nsStyleUnion") - .hide_type("nsStyleUnit") - .hide_type("nsStyleUserInterface") - .hide_type("nsStyleVariables") - .hide_type("nsStyleVisibility") - .hide_type("nsStyleXUL") - .hide_type("nsTimingFunction") - .hide_type("nscolor") - .hide_type("nscoord") - .hide_type("nsresult") - .hide_type("Loader") - .hide_type("ServoStyleSheet") - .hide_type("EffectCompositor_CascadeLevel") - .hide_type("UpdateAnimationsTasks") - .hide_type("nsTArrayBorrowed_uintptr_t") - .hide_type("ServoCssRulesStrong") - .hide_type("ServoCssRulesBorrowed") - .hide_type("ServoCssRulesBorrowedOrNull") - .hide_type("ServoCssRules") - .hide_type("RawServoStyleSheetStrong") - .hide_type("RawServoStyleSheetBorrowed") - .hide_type("RawServoStyleSheetBorrowedOrNull") - .hide_type("RawServoStyleSheet") - .hide_type("ServoComputedValuesStrong") - .hide_type("ServoComputedValuesBorrowed") - .hide_type("ServoComputedValuesBorrowedOrNull") - .hide_type("ServoComputedValues") - .hide_type("RawServoDeclarationBlockStrong") - .hide_type("RawServoDeclarationBlockBorrowed") - .hide_type("RawServoDeclarationBlockBorrowedOrNull") - .hide_type("RawServoStyleRuleStrong") - .hide_type("RawServoStyleRuleBorrowed") - .hide_type("RawServoStyleRuleBorrowedOrNull") - .hide_type("RawServoStyleRule") - .hide_type("RawServoImportRuleStrong") - .hide_type("RawServoImportRuleBorrowed") - .hide_type("RawServoImportRuleBorrowedOrNull") - .hide_type("RawServoImportRule") - .hide_type("RawServoAnimationValueStrong") - .hide_type("RawServoAnimationValueBorrowed") - .hide_type("RawServoAnimationValueBorrowedOrNull") - .hide_type("RawServoAnimationValueMapStrong") - .hide_type("RawServoAnimationValueMapBorrowed") - .hide_type("RawServoAnimationValueMapBorrowedOrNull") - .hide_type("RawServoMediaListStrong") - .hide_type("RawServoMediaListBorrowed") - .hide_type("RawServoMediaListBorrowedOrNull") - .hide_type("RawServoMediaList") - .hide_type("RawServoMediaRuleStrong") - .hide_type("RawServoMediaRuleBorrowed") - .hide_type("RawServoMediaRuleBorrowedOrNull") - .hide_type("RawServoMediaRule") - .hide_type("RawServoNamespaceRuleStrong") - .hide_type("RawServoNamespaceRuleBorrowed") - .hide_type("RawServoNamespaceRuleBorrowedOrNull") - .hide_type("RawServoNamespaceRule") - .hide_type("RawServoStyleSetOwned") - .hide_type("RawServoStyleSetOwnedOrNull") - .hide_type("RawServoStyleSetBorrowed") - .hide_type("RawServoStyleSetBorrowedOrNull") - .hide_type("RawServoStyleSetBorrowedMut") - .hide_type("RawServoStyleSetBorrowedMutOrNull") - .hide_type("RawServoStyleSet") - .hide_type("StyleChildrenIteratorOwned") - .hide_type("StyleChildrenIteratorOwnedOrNull") - .hide_type("StyleChildrenIteratorBorrowed") - .hide_type("StyleChildrenIteratorBorrowedOrNull") - .hide_type("StyleChildrenIteratorBorrowedMut") - .hide_type("StyleChildrenIteratorBorrowedMutOrNull") - .hide_type("StyleChildrenIterator") - .hide_type("ServoElementSnapshotOwned") - .hide_type("ServoElementSnapshotOwnedOrNull") - .hide_type("ServoElementSnapshotBorrowed") - .hide_type("ServoElementSnapshotBorrowedOrNull") - .hide_type("ServoElementSnapshotBorrowedMut") - .hide_type("ServoElementSnapshotBorrowedMutOrNull") - .hide_type("RawGeckoNodeBorrowed") - .hide_type("RawGeckoNodeBorrowedOrNull") - .hide_type("RawGeckoElementBorrowed") - .hide_type("RawGeckoElementBorrowedOrNull") - .hide_type("RawGeckoDocumentBorrowed") - .hide_type("RawGeckoDocumentBorrowedOrNull") - .hide_type("RawServoDeclarationBlockStrongBorrowed") - .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") - .hide_type("RawGeckoPresContextBorrowed") - .hide_type("RawGeckoPresContextBorrowedOrNull") - .hide_type("RawGeckoStyleAnimationListBorrowed") - .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") - .hide_type("nsCSSValueBorrowed") - .hide_type("nsCSSValueBorrowedOrNull") - .hide_type("nsCSSValueBorrowedMut") - .hide_type("nsCSSValueBorrowedMutOrNull") - .hide_type("nsTimingFunctionBorrowed") - .hide_type("nsTimingFunctionBorrowedOrNull") - .hide_type("nsTimingFunctionBorrowedMut") - .hide_type("nsTimingFunctionBorrowedMutOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowed") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") - .hide_type("RawGeckoAnimationValueListBorrowed") - .hide_type("RawGeckoAnimationValueListBorrowedOrNull") - .hide_type("RawGeckoAnimationValueListBorrowedMut") - .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") - .hide_type("RawGeckoComputedTimingBorrowed") - .hide_type("RawGeckoComputedTimingBorrowedOrNull") - .hide_type("RawGeckoComputedTimingBorrowedMut") - .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") - .hide_type("RawGeckoKeyframeListBorrowed") - .hide_type("RawGeckoKeyframeListBorrowedOrNull") - .hide_type("RawGeckoKeyframeListBorrowedMut") - .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowed") - .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowedMut") - .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") - .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) - .raw_line(r#"type nsACString_internal = nsACString;"#) - .raw_line(r#"type nsAString_internal = nsAString;"#) - .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) - .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) - .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) - .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) - .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) - .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) - .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) - .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) - .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) - .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) - .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) - .raw_line(r#"use gecko_bindings::structs::nsFont;"#) - .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) - .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) - .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) - .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) - .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) - .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) - .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) - .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) - .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) - .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) - .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) - .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) - .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) - .raw_line(r#"unsafe impl Send for nsStyleList {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) - .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) - .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) - .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) - .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) - .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) - .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) - .raw_line(r#"unsafe impl Send for nsStyleText {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) - .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) - .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) - .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) - .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) - .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) - .raw_line(r#"use gecko_bindings::structs::nscolor;"#) - .raw_line(r#"use gecko_bindings::structs::nscoord;"#) - .raw_line(r#"use gecko_bindings::structs::nsresult;"#) - .raw_line(r#"use gecko_bindings::structs::Loader;"#) - .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) - .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) - .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) - .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) - .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) - .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) - .raw_line(r#"enum ServoCssRulesVoid { }"#) - .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) - .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) - .raw_line(r#"enum RawServoStyleSheetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) - .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) - .raw_line(r#"enum ServoComputedValuesVoid { }"#) - .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) - .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) - .raw_line(r#"enum RawServoStyleRuleVoid { }"#) - .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) - .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) - .raw_line(r#"enum RawServoImportRuleVoid { }"#) - .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) - .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) - .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) - .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) - .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) - .raw_line(r#"enum RawServoMediaListVoid { }"#) - .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) - .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) - .raw_line(r#"enum RawServoMediaRuleVoid { }"#) - .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) - .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) - .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) - .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) - .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) - .raw_line(r#"enum RawServoStyleSetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) - .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) - .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) - .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) - .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) - .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) - .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) - .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("-std=c++14") - .clang_arg("-DTRACING=1") - .clang_arg("-DIMPL_LIBXUL") - .clang_arg("-DMOZ_STYLO_BINDINGS=1") - .clang_arg("-DMOZILLA_INTERNAL_API") - .clang_arg("-DRUST_BINDGEN") - .clang_arg("-DMOZ_STYLO") - .clang_arg("-DOS_POSIX=1") - .clang_arg("-DOS_LINUX=1") - .generate() - .expect("Should generate stylo bindings"); - - let now = Instant::now(); - - println!(""); - println!(""); - println!("Generated Stylo bindings in: {:?}", - now.duration_since(then)); - println!(""); - println!(""); - - // panic!("Uncomment this line to get timing logs"); -} +extern crate bindgen; + +/// A sanity test that we can generate bindings for Stylo. +/// +/// We don't assert on expected output because its just too big. The output will +/// change too often, and it won't be clear what is going on at a glance, unlike +/// the other tests with smaller input headers. +/// +/// This test is relatively slow, so we also only run it in release mode. +/// +/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing +/// how long bindings generation takes for Stylo. Stylo bindings generation +/// takes too long to be a proper `#[bench]`. +#[test] +#[cfg(not(any(debug_assertions, + feature = "testing_only_extra_assertions", + feature = "testing_only_llvm_stable")))] +fn sanity_check_can_generate_stylo_bindings() { + use std::time::Instant; + + let then = Instant::now(); + + bindgen::builder() + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) + .whitelisted_function("Servo_.*") + .whitelisted_function("Gecko_.*") + .hide_type("nsACString_internal") + .hide_type("nsAString_internal") + .hide_type("mozilla::css::URLValue") + .hide_type("RawGeckoAnimationPropertySegment") + .hide_type("RawGeckoComputedTiming") + .hide_type("RawGeckoDocument") + .hide_type("RawGeckoElement") + .hide_type("RawGeckoKeyframeList") + .hide_type("RawGeckoComputedKeyframeValuesList") + .hide_type("RawGeckoFontFaceRuleList") + .hide_type("RawGeckoNode") + .hide_type("RawGeckoAnimationValueList") + .hide_type("RawServoAnimationValue") + .hide_type("RawServoAnimationValueMap") + .hide_type("RawServoDeclarationBlock") + .hide_type("RawGeckoPresContext") + .hide_type("RawGeckoPresContextOwned") + .hide_type("RawGeckoStyleAnimationList") + .hide_type("RawGeckoURLExtraData") + .hide_type("RefPtr") + .hide_type("CSSPseudoClassType") + .hide_type("TraversalRootBehavior") + .hide_type("ComputedTimingFunction_BeforeFlag") + .hide_type("FontFamilyList") + .hide_type("FontFamilyType") + .hide_type("Keyframe") + .hide_type("ServoBundledURI") + .hide_type("ServoElementSnapshot") + .hide_type("SheetParsingMode") + .hide_type("StyleBasicShape") + .hide_type("StyleBasicShapeType") + .hide_type("StyleShapeSource") + .hide_type("nsCSSFontFaceRule") + .hide_type("nsCSSKeyword") + .hide_type("nsCSSPropertyID") + .hide_type("nsCSSShadowArray") + .hide_type("nsCSSUnit") + .hide_type("nsCSSValue") + .hide_type("nsCSSValueSharedList") + .hide_type("nsChangeHint") + .hide_type("nsCursorImage") + .hide_type("nsFont") + .hide_type("nsIAtom") + .hide_type("nsMediaFeature") + .hide_type("nsRestyleHint") + .hide_type("nsStyleBackground") + .hide_type("nsStyleBorder") + .hide_type("nsStyleColor") + .hide_type("nsStyleColumn") + .hide_type("nsStyleContent") + .hide_type("nsStyleContentData") + .hide_type("nsStyleContentType") + .hide_type("nsStyleContext") + .hide_type("nsStyleCoord") + .hide_type("nsStyleCoord_Calc") + .hide_type("nsStyleCoord_CalcValue") + .hide_type("nsStyleDisplay") + .hide_type("nsStyleEffects") + .hide_type("nsStyleFilter") + .hide_type("nsStyleFont") + .hide_type("nsStyleGradient") + .hide_type("nsStyleGradientStop") + .hide_type("nsStyleImage") + .hide_type("nsStyleImageLayers") + .hide_type("nsStyleImageLayers_Layer") + .hide_type("nsStyleImageLayers_LayerType") + .hide_type("nsStyleImageRequest") + .hide_type("nsStyleList") + .hide_type("nsStyleMargin") + .hide_type("nsStyleOutline") + .hide_type("nsStylePadding") + .hide_type("nsStylePosition") + .hide_type("nsStyleQuoteValues") + .hide_type("nsStyleSVG") + .hide_type("nsStyleSVGPaint") + .hide_type("nsStyleSVGReset") + .hide_type("nsStyleTable") + .hide_type("nsStyleTableBorder") + .hide_type("nsStyleText") + .hide_type("nsStyleTextReset") + .hide_type("nsStyleUIReset") + .hide_type("nsStyleUnion") + .hide_type("nsStyleUnit") + .hide_type("nsStyleUserInterface") + .hide_type("nsStyleVariables") + .hide_type("nsStyleVisibility") + .hide_type("nsStyleXUL") + .hide_type("nsTimingFunction") + .hide_type("nscolor") + .hide_type("nscoord") + .hide_type("nsresult") + .hide_type("Loader") + .hide_type("ServoStyleSheet") + .hide_type("EffectCompositor_CascadeLevel") + .hide_type("UpdateAnimationsTasks") + .hide_type("nsTArrayBorrowed_uintptr_t") + .hide_type("ServoCssRulesStrong") + .hide_type("ServoCssRulesBorrowed") + .hide_type("ServoCssRulesBorrowedOrNull") + .hide_type("ServoCssRules") + .hide_type("RawServoStyleSheetStrong") + .hide_type("RawServoStyleSheetBorrowed") + .hide_type("RawServoStyleSheetBorrowedOrNull") + .hide_type("RawServoStyleSheet") + .hide_type("ServoComputedValuesStrong") + .hide_type("ServoComputedValuesBorrowed") + .hide_type("ServoComputedValuesBorrowedOrNull") + .hide_type("ServoComputedValues") + .hide_type("RawServoDeclarationBlockStrong") + .hide_type("RawServoDeclarationBlockBorrowed") + .hide_type("RawServoDeclarationBlockBorrowedOrNull") + .hide_type("RawServoStyleRuleStrong") + .hide_type("RawServoStyleRuleBorrowed") + .hide_type("RawServoStyleRuleBorrowedOrNull") + .hide_type("RawServoStyleRule") + .hide_type("RawServoImportRuleStrong") + .hide_type("RawServoImportRuleBorrowed") + .hide_type("RawServoImportRuleBorrowedOrNull") + .hide_type("RawServoImportRule") + .hide_type("RawServoAnimationValueStrong") + .hide_type("RawServoAnimationValueBorrowed") + .hide_type("RawServoAnimationValueBorrowedOrNull") + .hide_type("RawServoAnimationValueMapStrong") + .hide_type("RawServoAnimationValueMapBorrowed") + .hide_type("RawServoAnimationValueMapBorrowedOrNull") + .hide_type("RawServoMediaListStrong") + .hide_type("RawServoMediaListBorrowed") + .hide_type("RawServoMediaListBorrowedOrNull") + .hide_type("RawServoMediaList") + .hide_type("RawServoMediaRuleStrong") + .hide_type("RawServoMediaRuleBorrowed") + .hide_type("RawServoMediaRuleBorrowedOrNull") + .hide_type("RawServoMediaRule") + .hide_type("RawServoNamespaceRuleStrong") + .hide_type("RawServoNamespaceRuleBorrowed") + .hide_type("RawServoNamespaceRuleBorrowedOrNull") + .hide_type("RawServoNamespaceRule") + .hide_type("RawServoStyleSetOwned") + .hide_type("RawServoStyleSetOwnedOrNull") + .hide_type("RawServoStyleSetBorrowed") + .hide_type("RawServoStyleSetBorrowedOrNull") + .hide_type("RawServoStyleSetBorrowedMut") + .hide_type("RawServoStyleSetBorrowedMutOrNull") + .hide_type("RawServoStyleSet") + .hide_type("StyleChildrenIteratorOwned") + .hide_type("StyleChildrenIteratorOwnedOrNull") + .hide_type("StyleChildrenIteratorBorrowed") + .hide_type("StyleChildrenIteratorBorrowedOrNull") + .hide_type("StyleChildrenIteratorBorrowedMut") + .hide_type("StyleChildrenIteratorBorrowedMutOrNull") + .hide_type("StyleChildrenIterator") + .hide_type("ServoElementSnapshotOwned") + .hide_type("ServoElementSnapshotOwnedOrNull") + .hide_type("ServoElementSnapshotBorrowed") + .hide_type("ServoElementSnapshotBorrowedOrNull") + .hide_type("ServoElementSnapshotBorrowedMut") + .hide_type("ServoElementSnapshotBorrowedMutOrNull") + .hide_type("RawGeckoNodeBorrowed") + .hide_type("RawGeckoNodeBorrowedOrNull") + .hide_type("RawGeckoElementBorrowed") + .hide_type("RawGeckoElementBorrowedOrNull") + .hide_type("RawGeckoDocumentBorrowed") + .hide_type("RawGeckoDocumentBorrowedOrNull") + .hide_type("RawServoDeclarationBlockStrongBorrowed") + .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") + .hide_type("RawGeckoPresContextBorrowed") + .hide_type("RawGeckoPresContextBorrowedOrNull") + .hide_type("RawGeckoStyleAnimationListBorrowed") + .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") + .hide_type("nsCSSValueBorrowed") + .hide_type("nsCSSValueBorrowedOrNull") + .hide_type("nsCSSValueBorrowedMut") + .hide_type("nsCSSValueBorrowedMutOrNull") + .hide_type("nsTimingFunctionBorrowed") + .hide_type("nsTimingFunctionBorrowedOrNull") + .hide_type("nsTimingFunctionBorrowedMut") + .hide_type("nsTimingFunctionBorrowedMutOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowed") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") + .hide_type("RawGeckoAnimationValueListBorrowed") + .hide_type("RawGeckoAnimationValueListBorrowedOrNull") + .hide_type("RawGeckoAnimationValueListBorrowedMut") + .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") + .hide_type("RawGeckoComputedTimingBorrowed") + .hide_type("RawGeckoComputedTimingBorrowedOrNull") + .hide_type("RawGeckoComputedTimingBorrowedMut") + .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") + .hide_type("RawGeckoKeyframeListBorrowed") + .hide_type("RawGeckoKeyframeListBorrowedOrNull") + .hide_type("RawGeckoKeyframeListBorrowedMut") + .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowed") + .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowedMut") + .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") + .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) + .raw_line(r#"type nsACString_internal = nsACString;"#) + .raw_line(r#"type nsAString_internal = nsAString;"#) + .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) + .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) + .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) + .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) + .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) + .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) + .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) + .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) + .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) + .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) + .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) + .raw_line(r#"use gecko_bindings::structs::nsFont;"#) + .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) + .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) + .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) + .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) + .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) + .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) + .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) + .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) + .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) + .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) + .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) + .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) + .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) + .raw_line(r#"unsafe impl Send for nsStyleList {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) + .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) + .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) + .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) + .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) + .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) + .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) + .raw_line(r#"unsafe impl Send for nsStyleText {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) + .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) + .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) + .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) + .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) + .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) + .raw_line(r#"use gecko_bindings::structs::nscolor;"#) + .raw_line(r#"use gecko_bindings::structs::nscoord;"#) + .raw_line(r#"use gecko_bindings::structs::nsresult;"#) + .raw_line(r#"use gecko_bindings::structs::Loader;"#) + .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) + .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) + .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) + .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) + .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) + .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) + .raw_line(r#"enum ServoCssRulesVoid { }"#) + .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) + .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) + .raw_line(r#"enum RawServoStyleSheetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) + .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) + .raw_line(r#"enum ServoComputedValuesVoid { }"#) + .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) + .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) + .raw_line(r#"enum RawServoStyleRuleVoid { }"#) + .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) + .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) + .raw_line(r#"enum RawServoImportRuleVoid { }"#) + .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) + .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) + .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) + .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) + .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) + .raw_line(r#"enum RawServoMediaListVoid { }"#) + .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) + .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) + .raw_line(r#"enum RawServoMediaRuleVoid { }"#) + .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) + .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) + .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) + .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) + .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) + .raw_line(r#"enum RawServoStyleSetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) + .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) + .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) + .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) + .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) + .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) + .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) + .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) + .clang_arg("-x") + .clang_arg("c++") + .clang_arg("-std=c++14") + .clang_arg("-DTRACING=1") + .clang_arg("-DIMPL_LIBXUL") + .clang_arg("-DMOZ_STYLO_BINDINGS=1") + .clang_arg("-DMOZILLA_INTERNAL_API") + .clang_arg("-DRUST_BINDGEN") + .clang_arg("-DMOZ_STYLO") + .clang_arg("-DOS_POSIX=1") + .clang_arg("-DOS_LINUX=1") + .generate() + .expect("Should generate stylo bindings"); + + let now = Instant::now(); + + println!(""); + println!(""); + println!("Generated Stylo bindings in: {:?}", + now.duration_since(then)); + println!(""); + println!(""); + + // panic!("Uncomment this line to get timing logs"); +} diff --git a/tests/tests.rs b/tests/tests.rs index 8b017b54c8..84506aa05d 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,171 +1,171 @@ -extern crate clap; -extern crate diff; -extern crate bindgen; -extern crate shlex; - -use bindgen::{Builder, builder}; -use std::fs; -use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; -use std::path::PathBuf; - -#[path="../src/options.rs"] -mod options; -use options::builder_from_flags; - -fn compare_generated_header(header: &PathBuf, - builder: Builder) - -> Result<(), Error> { - let file_name = - try!(header - .file_name() - .ok_or(Error::new(ErrorKind::Other, - "spawn_bindgen expects a file"))); - - let mut expected = PathBuf::from(header); - expected.pop(); - expected.pop(); - expected.push("expectations"); - expected.push("tests"); - expected.push(file_name); - expected.set_extension("rs"); - - // We skip the generate() error here so we get a full diff below - let output = match builder.generate() { - Ok(bindings) => bindings.to_string(), - Err(_) => "".to_string(), - }; - - let mut buffer = String::new(); - { - if let Ok(expected_file) = fs::File::open(&expected) { - try!(BufReader::new(expected_file).read_to_string(&mut buffer)); - } - } - - if output == buffer { - if !output.is_empty() { - return Ok(()); - } - return Err(Error::new(ErrorKind::Other, - "Something's gone really wrong!")); - } - - println!("diff expected generated"); - println!("--- expected: {:?}", expected); - println!("+++ generated from: {:?}", header); - - for diff in diff::lines(&buffer, &output) { - match diff { - diff::Result::Left(l) => println!("-{}", l), - diff::Result::Both(l, _) => println!(" {}", l), - diff::Result::Right(r) => println!("+{}", r), - } - } - - // Override the diff. - { - let mut expected_file = try!(fs::File::create(&expected)); - try!(expected_file.write_all(output.as_bytes())); - } - - Err(Error::new(ErrorKind::Other, "Header and binding differ!")) -} - -fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { - let source = try!(fs::File::open(header)); - let reader = BufReader::new(source); - - // Scoop up bindgen-flags from test header - let mut flags = Vec::with_capacity(2); - - for line in reader.lines().take(3) { - let line = try!(line); - if line.contains("bindgen-flags: ") { - let extra_flags = line.split("bindgen-flags: ") - .last() - .and_then(shlex::split) - .unwrap(); - flags.extend(extra_flags.into_iter()); - } else if line.contains("bindgen-unstable") && - cfg!(feature = "testing_only_llvm_stable") { - return Ok(None); - } else if line.contains("bindgen-osx-only") { - let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; - flags = prepend_flags - .into_iter() - .map(ToString::to_string) - .chain(flags) - .collect(); - } - } - - // Fool builder_from_flags() into believing it has real env::args_os... - // - add "bindgen" as executable name 0th element - // - add header filename as 1st element - // - prepend raw lines so they're in the right order for expected output - // - append the test header's bindgen flags - let header_str = try!(header - .to_str() - .ok_or(Error::new(ErrorKind::Other, - "Invalid header file name"))); - - let prepend = ["bindgen", - "--with-derive-default", - header_str, - "--raw-line", - "", - "--raw-line", - "#![allow(non_snake_case)]", - "--raw-line", - ""]; - - let args = prepend - .into_iter() - .map(ToString::to_string) - .chain(flags.into_iter()); - - builder_from_flags(args).map(|(builder, _, _)| { - Some(builder.no_unstable_rust()) - }) -} - -macro_rules! test_header { - ($function:ident, $header:expr) => ( - #[test] - fn $function() { - let header = PathBuf::from($header); - let result = create_bindgen_builder(&header) - .and_then(|builder| { - if let Some(builder) = builder { - compare_generated_header(&header, builder) - } else { - Ok(()) - } - }); - - if let Err(err) = result { - panic!("{}", err); - } - } - ) -} - -// This file is generated by build.rs -include!(concat!(env!("OUT_DIR"), "/tests.rs")); - -#[test] -fn test_header_contents() { - let bindings = builder() - .header_contents("test.h", "int foo(const char* a);") - .no_unstable_rust() - .generate() - .unwrap() - .to_string(); - assert_eq!(bindings, - "/* automatically generated by rust-bindgen */ - -extern \"C\" { - pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -"); -} +extern crate clap; +extern crate diff; +extern crate bindgen; +extern crate shlex; + +use bindgen::{Builder, builder}; +use std::fs; +use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; +use std::path::PathBuf; + +#[path="../src/options.rs"] +mod options; +use options::builder_from_flags; + +fn compare_generated_header(header: &PathBuf, + builder: Builder) + -> Result<(), Error> { + let file_name = + try!(header + .file_name() + .ok_or(Error::new(ErrorKind::Other, + "spawn_bindgen expects a file"))); + + let mut expected = PathBuf::from(header); + expected.pop(); + expected.pop(); + expected.push("expectations"); + expected.push("tests"); + expected.push(file_name); + expected.set_extension("rs"); + + // We skip the generate() error here so we get a full diff below + let output = match builder.generate() { + Ok(bindings) => bindings.to_string(), + Err(_) => "".to_string(), + }; + + let mut buffer = String::new(); + { + if let Ok(expected_file) = fs::File::open(&expected) { + try!(BufReader::new(expected_file).read_to_string(&mut buffer)); + } + } + + if output == buffer { + if !output.is_empty() { + return Ok(()); + } + return Err(Error::new(ErrorKind::Other, + "Something's gone really wrong!")); + } + + println!("diff expected generated"); + println!("--- expected: {:?}", expected); + println!("+++ generated from: {:?}", header); + + for diff in diff::lines(&buffer, &output) { + match diff { + diff::Result::Left(l) => println!("-{}", l), + diff::Result::Both(l, _) => println!(" {}", l), + diff::Result::Right(r) => println!("+{}", r), + } + } + + // Override the diff. + { + let mut expected_file = try!(fs::File::create(&expected)); + try!(expected_file.write_all(output.as_bytes())); + } + + Err(Error::new(ErrorKind::Other, "Header and binding differ!")) +} + +fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { + let source = try!(fs::File::open(header)); + let reader = BufReader::new(source); + + // Scoop up bindgen-flags from test header + let mut flags = Vec::with_capacity(2); + + for line in reader.lines().take(3) { + let line = try!(line); + if line.contains("bindgen-flags: ") { + let extra_flags = line.split("bindgen-flags: ") + .last() + .and_then(shlex::split) + .unwrap(); + flags.extend(extra_flags.into_iter()); + } else if line.contains("bindgen-unstable") && + cfg!(feature = "testing_only_llvm_stable") { + return Ok(None); + } else if line.contains("bindgen-osx-only") { + let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; + flags = prepend_flags + .into_iter() + .map(ToString::to_string) + .chain(flags) + .collect(); + } + } + + // Fool builder_from_flags() into believing it has real env::args_os... + // - add "bindgen" as executable name 0th element + // - add header filename as 1st element + // - prepend raw lines so they're in the right order for expected output + // - append the test header's bindgen flags + let header_str = try!(header + .to_str() + .ok_or(Error::new(ErrorKind::Other, + "Invalid header file name"))); + + let prepend = ["bindgen", + "--with-derive-default", + header_str, + "--raw-line", + "", + "--raw-line", + "#![allow(non_snake_case)]", + "--raw-line", + ""]; + + let args = prepend + .into_iter() + .map(ToString::to_string) + .chain(flags.into_iter()); + + builder_from_flags(args).map(|(builder, _, _)| { + Some(builder.no_unstable_rust()) + }) +} + +macro_rules! test_header { + ($function:ident, $header:expr) => ( + #[test] + fn $function() { + let header = PathBuf::from($header); + let result = create_bindgen_builder(&header) + .and_then(|builder| { + if let Some(builder) = builder { + compare_generated_header(&header, builder) + } else { + Ok(()) + } + }); + + if let Err(err) = result { + panic!("{}", err); + } + } + ) +} + +// This file is generated by build.rs +include!(concat!(env!("OUT_DIR"), "/tests.rs")); + +#[test] +fn test_header_contents() { + let bindings = builder() + .header_contents("test.h", "int foo(const char* a);") + .no_unstable_rust() + .generate() + .unwrap() + .to_string(); + assert_eq!(bindings, + "/* automatically generated by rust-bindgen */ + +extern \"C\" { + pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +"); +} From d305715afb5310ccbe807a6763398c86b3b20c13 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 18:49:57 -0400 Subject: [PATCH 16/18] Somehow these tests failed even though they are the same? --- .../tests/anonymous-template-types.rs | 70 +-- tests/expectations/tests/class_nested.rs | 264 ++++----- tests/expectations/tests/class_with_dtor.rs | 94 +-- tests/expectations/tests/const_tparam.rs | 32 +- .../tests/default-template-parameter.rs | 64 +- .../tests/forward-declaration-autoptr.rs | 82 +-- .../forward-inherit-struct-with-fields.rs | 50 +- tests/expectations/tests/inherit_named.rs | 40 +- ...issue-584-stylo-template-analysis-panic.rs | 162 ++--- tests/expectations/tests/namespace.rs | 206 +++---- tests/expectations/tests/nsStyleAutoArray.rs | 60 +- .../tests/replace_template_alias.rs | 38 +- tests/expectations/tests/replaces_double.rs | 38 +- .../tests/template-param-usage-0.rs | 30 +- .../tests/template-param-usage-10.rs | 58 +- .../tests/template-param-usage-12.rs | 50 +- .../tests/template-param-usage-13.rs | 42 +- .../tests/template-param-usage-15.rs | 48 +- .../tests/template-param-usage-2.rs | 48 +- .../tests/template-param-usage-3.rs | 54 +- .../tests/template-param-usage-4.rs | 40 +- .../tests/template-param-usage-5.rs | 32 +- .../tests/template-param-usage-7.rs | 36 +- .../tests/template-param-usage-8.rs | 38 +- .../tests/template-param-usage-9.rs | 48 +- tests/expectations/tests/template.rs | 558 +++++++++--------- tests/expectations/tests/template_alias.rs | 32 +- .../tests/template_alias_namespace.rs | 58 +- .../template_typedef_transitive_param.rs | 42 +- ..._alias_partial_template_especialization.rs | 32 +- tests/expectations/tests/using.rs | 36 +- tests/expectations/tests/what_is_going_on.rs | 66 +-- tests/expectations/tests/whitelist_basic.rs | 50 +- 33 files changed, 1299 insertions(+), 1299 deletions(-) diff --git a/tests/expectations/tests/anonymous-template-types.rs b/tests/expectations/tests/anonymous-template-types.rs index d5e712dd15..50604a3f1b 100644 --- a/tests/expectations/tests/anonymous-template-types.rs +++ b/tests/expectations/tests/anonymous-template-types.rs @@ -1,35 +1,35 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t_member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Bar { - pub member: ::std::os::raw::c_char, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Quux { - pub v_member: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Quux { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Lobo { - pub also_member: ::std::os::raw::c_char, -} -pub type AliasWithAnonType = ::std::os::raw::c_char; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t_member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Bar { + pub member: ::std::os::raw::c_char, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Quux { + pub v_member: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Quux { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Lobo { + pub also_member: ::std::os::raw::c_char, +} +pub type AliasWithAnonType = ::std::os::raw::c_char; diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index 60f8633625..8446cbcdf6 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -1,132 +1,132 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub member_a: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_B { - pub member_b: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_B() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_B ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_B ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_B ) , "::" , - stringify ! ( member_b ) )); -} -impl Clone for A_B { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A_C { - pub baz: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_A_C() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A_C ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A_C ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A_C ) , "::" , - stringify ! ( baz ) )); -} -impl Clone for A_C { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct A_D { - pub foo: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for A_D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , stringify - ! ( member_a ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -extern "C" { - #[link_name = "var"] - pub static mut var: A_B; -} -#[test] -fn __bindgen_test_layout_A_D_instantiation_16() { - assert_eq!(::std::mem::size_of::>() , 4usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 4usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - A_D<::std::os::raw::c_int> ) )); -} -extern "C" { - #[link_name = "baz"] - pub static mut baz: A_D<::std::os::raw::c_int>; -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct D { - pub member: A_B, -} -#[test] -fn bindgen_test_layout_D() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( D ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( D ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const D ) ) . member as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( D ) , "::" , stringify - ! ( member ) )); -} -impl Clone for D { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Templated_Templated_inner { - pub member_ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Templated_Templated_inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for Templated { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub member_a: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_B { + pub member_b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_B() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_B ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_B ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_B ) ) . member_b as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_B ) , "::" , + stringify ! ( member_b ) )); +} +impl Clone for A_B { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A_C { + pub baz: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_A_C() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A_C ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A_C ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A_C ) ) . baz as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A_C ) , "::" , + stringify ! ( baz ) )); +} +impl Clone for A_C { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct A_D { + pub foo: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for A_D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . member_a as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , stringify + ! ( member_a ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +extern "C" { + #[link_name = "var"] + pub static mut var: A_B; +} +#[test] +fn __bindgen_test_layout_A_D_instantiation_16() { + assert_eq!(::std::mem::size_of::>() , 4usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 4usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + A_D<::std::os::raw::c_int> ) )); +} +extern "C" { + #[link_name = "baz"] + pub static mut baz: A_D<::std::os::raw::c_int>; +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct D { + pub member: A_B, +} +#[test] +fn bindgen_test_layout_D() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( D ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( D ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const D ) ) . member as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( D ) , "::" , stringify + ! ( member ) )); +} +impl Clone for D { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Templated_Templated_inner { + pub member_ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Templated_Templated_inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for Templated { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 60464cc2a6..3b15b89138 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -1,47 +1,47 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct HandleWithDtor { - pub ptr: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for HandleWithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct WithoutDtor { - pub shouldBeWithDtor: HandleValue, -} -#[test] -fn bindgen_test_layout_WithoutDtor() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( WithoutDtor ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( WithoutDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , - stringify ! ( shouldBeWithDtor ) )); -} -impl Default for WithoutDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { - assert_eq!(::std::mem::size_of::>() - , 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() - , 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - HandleWithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct HandleWithDtor { + pub ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for HandleWithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct WithoutDtor { + pub shouldBeWithDtor: HandleValue, +} +#[test] +fn bindgen_test_layout_WithoutDtor() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( WithoutDtor ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( WithoutDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const WithoutDtor ) ) . shouldBeWithDtor as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( WithoutDtor ) , "::" , + stringify ! ( shouldBeWithDtor ) )); +} +impl Default for WithoutDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { + assert_eq!(::std::mem::size_of::>() + , 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() + , 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + HandleWithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/const_tparam.rs b/tests/expectations/tests/const_tparam.rs index aaa89f9c92..7600e18eed 100644 --- a/tests/expectations/tests/const_tparam.rs +++ b/tests/expectations/tests/const_tparam.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct C { - pub foo: *const T, - pub bar: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct C { + pub foo: *const T, + pub bar: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/default-template-parameter.rs b/tests/expectations/tests/default-template-parameter.rs index 70207694a1..c098dac7b5 100644 --- a/tests/expectations/tests/default-template-parameter.rs +++ b/tests/expectations/tests/default-template-parameter.rs @@ -1,32 +1,32 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { - pub t: T, - pub u: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_6() { - assert_eq!(::std::mem::size_of::>() , - 8usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Foo ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo ) )); -} -extern "C" { - #[link_name = "_ZL3bar"] - pub static mut bar: Foo; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub t: T, + pub u: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_6() { + assert_eq!(::std::mem::size_of::>() , + 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Foo ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo ) )); +} +extern "C" { + #[link_name = "_ZL3bar"] + pub static mut bar: Foo; +} diff --git a/tests/expectations/tests/forward-declaration-autoptr.rs b/tests/expectations/tests/forward-declaration-autoptr.rs index acd5b535f2..3b5e261618 100644 --- a/tests/expectations/tests/forward-declaration-autoptr.rs +++ b/tests/expectations/tests/forward-declaration-autoptr.rs @@ -1,41 +1,41 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo([u8; 0]); -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr { - pub m_inner: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for RefPtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct Bar { - pub m_member: RefPtr, -} -#[test] -fn bindgen_test_layout_Bar() { - assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( - "Size of: " , stringify ! ( Bar ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( Bar ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( Bar ) , "::" , - stringify ! ( m_member ) )); -} -impl Clone for Bar { - fn clone(&self) -> Self { *self } -} -impl Default for Bar { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo([u8; 0]); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr { + pub m_inner: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for RefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Bar { + pub m_member: RefPtr, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::() , 8usize , concat ! ( + "Size of: " , stringify ! ( Bar ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( Bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Bar ) ) . m_member as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Bar ) , "::" , + stringify ! ( m_member ) )); +} +impl Clone for Bar { + fn clone(&self) -> Self { *self } +} +impl Default for Bar { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/forward-inherit-struct-with-fields.rs b/tests/expectations/tests/forward-inherit-struct-with-fields.rs index 4a61631995..1b31f62b57 100644 --- a/tests/expectations/tests/forward-inherit-struct-with-fields.rs +++ b/tests/expectations/tests/forward-inherit-struct-with-fields.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub _base: js_RootedBase, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct js_RootedBase { - pub foo: *mut T, - pub next: *mut Rooted, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for js_RootedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub _base: js_RootedBase, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct js_RootedBase { + pub foo: *mut T, + pub next: *mut Rooted, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for js_RootedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index e67a55a76d..a641de70b5 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wohoo { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Weeee { - pub _base: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Weeee { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wohoo { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Weeee { + pub _base: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Weeee { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs index e83d5800b5..ddcaf3fc0b 100644 --- a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs +++ b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs @@ -1,81 +1,81 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - -pub type RefPtr = T; - -#[repr(C)] -#[derive(Debug, Copy)] -pub struct b { - pub _base: g, -} -#[test] -fn bindgen_test_layout_b() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( b ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( b ) )); -} -impl Clone for b { - fn clone(&self) -> Self { *self } -} -impl Default for b { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct A { - pub _address: u8, -} -pub type A_a = b; -#[test] -fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); -} -impl Clone for A { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct e { - pub d: RefPtr, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for e { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct f { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct g { - pub h: f, -} -#[test] -fn bindgen_test_layout_g() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( g ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( g ) )); - assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( g ) , "::" , stringify - ! ( h ) )); -} -impl Clone for g { - fn clone(&self) -> Self { *self } -} -impl Default for g { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z25Servo_Element_GetSnapshotv"] - pub fn Servo_Element_GetSnapshot() -> A; -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +pub type RefPtr = T; + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct b { + pub _base: g, +} +#[test] +fn bindgen_test_layout_b() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( b ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( b ) )); +} +impl Clone for b { + fn clone(&self) -> Self { *self } +} +impl Default for b { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct A { + pub _address: u8, +} +pub type A_a = b; +#[test] +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); +} +impl Clone for A { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct e { + pub d: RefPtr, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for e { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct f { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct g { + pub h: f, +} +#[test] +fn bindgen_test_layout_g() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( g ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( g ) )); + assert_eq! (unsafe { & ( * ( 0 as * const g ) ) . h as * const _ as usize + } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( g ) , "::" , stringify + ! ( h ) )); +} +impl Clone for g { + fn clone(&self) -> Self { *self } +} +impl Default for g { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z25Servo_Element_GetSnapshotv"] + pub fn Servo_Element_GetSnapshot() -> A; +} diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs index 7520f03d8d..86d5e89247 100644 --- a/tests/expectations/tests/namespace.rs +++ b/tests/expectations/tests/namespace.rs @@ -1,103 +1,103 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - extern "C" { - #[link_name = "_Z9top_levelv"] - pub fn top_level(); - } - pub mod whatever { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_int; - extern "C" { - #[link_name = "_ZN8whatever11in_whateverEv"] - pub fn in_whatever(); - } - } - pub mod _bindgen_mod_id_13 { - #[allow(unused_imports)] - use self::super::super::root; - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_13fooEv"] - pub fn foo(); - } - #[repr(C)] - #[derive(Debug, Default, Copy)] - pub struct A { - pub b: root::whatever::whatever_int_t, - } - #[test] - fn bindgen_test_layout_A() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( A ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( A ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const A ) ) . b as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( A ) , "::" , - stringify ! ( b ) )); - } - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] - pub fn A_lets_hope_this_works(this: - *mut root::_bindgen_mod_id_13::A) - -> ::std::os::raw::c_int; - } - impl Clone for A { - fn clone(&self) -> Self { *self } - } - impl A { - #[inline] - pub unsafe fn lets_hope_this_works(&mut self) - -> ::std::os::raw::c_int { - A_lets_hope_this_works(self) - } - } - } - #[repr(C)] - #[derive(Debug)] - pub struct C { - pub _base: root::_bindgen_mod_id_13::A, - pub m_c: T, - pub m_c_ptr: *mut T, - pub m_c_arr: [T; 10usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - pub mod w { - #[allow(unused_imports)] - use self::super::super::root; - pub type whatever_int_t = ::std::os::raw::c_uint; - #[repr(C)] - #[derive(Debug)] - pub struct D { - pub m_c: root::C, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - extern "C" { - #[link_name = "_ZN1w3hehEv"] - pub fn heh() -> root::w::whatever_int_t; - } - extern "C" { - #[link_name = "_ZN1w3fooEv"] - pub fn foo() -> root::C<::std::os::raw::c_int>; - } - extern "C" { - #[link_name = "_ZN1w4barrEv"] - pub fn barr() -> root::C; - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + extern "C" { + #[link_name = "_Z9top_levelv"] + pub fn top_level(); + } + pub mod whatever { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_int; + extern "C" { + #[link_name = "_ZN8whatever11in_whateverEv"] + pub fn in_whatever(); + } + } + pub mod _bindgen_mod_id_13 { + #[allow(unused_imports)] + use self::super::super::root; + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_13fooEv"] + pub fn foo(); + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct A { + pub b: root::whatever::whatever_int_t, + } + #[test] + fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( A ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( A ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const A ) ) . b as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( A ) , "::" , + stringify ! ( b ) )); + } + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_11A20lets_hope_this_worksEv"] + pub fn A_lets_hope_this_works(this: + *mut root::_bindgen_mod_id_13::A) + -> ::std::os::raw::c_int; + } + impl Clone for A { + fn clone(&self) -> Self { *self } + } + impl A { + #[inline] + pub unsafe fn lets_hope_this_works(&mut self) + -> ::std::os::raw::c_int { + A_lets_hope_this_works(self) + } + } + } + #[repr(C)] + #[derive(Debug)] + pub struct C { + pub _base: root::_bindgen_mod_id_13::A, + pub m_c: T, + pub m_c_ptr: *mut T, + pub m_c_arr: [T; 10usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for C { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + pub mod w { + #[allow(unused_imports)] + use self::super::super::root; + pub type whatever_int_t = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug)] + pub struct D { + pub m_c: root::C, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + extern "C" { + #[link_name = "_ZN1w3hehEv"] + pub fn heh() -> root::w::whatever_int_t; + } + extern "C" { + #[link_name = "_ZN1w3fooEv"] + pub fn foo() -> root::C<::std::os::raw::c_int>; + } + extern "C" { + #[link_name = "_ZN1w4barrEv"] + pub fn barr() -> root::C; + } + } +} diff --git a/tests/expectations/tests/nsStyleAutoArray.rs b/tests/expectations/tests/nsStyleAutoArray.rs index 239dfbdd2b..04f01c0c3d 100644 --- a/tests/expectations/tests/nsStyleAutoArray.rs +++ b/tests/expectations/tests/nsStyleAutoArray.rs @@ -1,30 +1,30 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsTArray { - pub mBuff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for nsTArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsStyleAutoArray { - pub mFirstElement: T, - pub mOtherElements: nsTArray, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum nsStyleAutoArray_WithSingleInitialElement { - WITH_SINGLE_INITIAL_ELEMENT = 0, -} -impl Default for nsStyleAutoArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsTArray { + pub mBuff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsTArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsStyleAutoArray { + pub mFirstElement: T, + pub mOtherElements: nsTArray, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum nsStyleAutoArray_WithSingleInitialElement { + WITH_SINGLE_INITIAL_ELEMENT = 0, +} +impl Default for nsStyleAutoArray { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replace_template_alias.rs b/tests/expectations/tests/replace_template_alias.rs index efe507157b..65a5332b9a 100644 --- a/tests/expectations/tests/replace_template_alias.rs +++ b/tests/expectations/tests/replace_template_alias.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -/// But the replacement type does use T! -/// -///
-pub type JS_detail_MaybeWrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +/// But the replacement type does use T! +/// +///
+pub type JS_detail_MaybeWrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/replaces_double.rs b/tests/expectations/tests/replaces_double.rs index 4177889385..f7093d3d65 100644 --- a/tests/expectations/tests/replaces_double.rs +++ b/tests/expectations/tests/replaces_double.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: Rooted_MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -/** - *
- */ -pub type Rooted_MaybeWrapped = T; -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: Rooted_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +/** + *
+ */ +pub type Rooted_MaybeWrapped = T; +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs index a30d52f9f0..a36d729a4e 100644 --- a/tests/expectations/tests/template-param-usage-0.rs +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -1,15 +1,15 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs index 0bfd6ad6e0..d41740cd7a 100644 --- a/tests/expectations/tests/template-param-usage-10.rs +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage { - pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type DoublyIndirectUsage_Aliased = T; -pub type DoublyIndirectUsage_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoublyIndirectUsage_IndirectUsage { - pub member: DoublyIndirectUsage_Aliased, - pub another: DoublyIndirectUsage_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoublyIndirectUsage_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for DoublyIndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage { + pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type DoublyIndirectUsage_Aliased = T; +pub type DoublyIndirectUsage_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage_IndirectUsage { + pub member: DoublyIndirectUsage_Aliased, + pub another: DoublyIndirectUsage_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoublyIndirectUsage_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for DoublyIndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs index c3494b4fc6..fcf10615f0 100644 --- a/tests/expectations/tests/template-param-usage-12.rs +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub t: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseUsesT>, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub t: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseUsesT>, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs index d4b52494e9..10e45ed1f0 100644 --- a/tests/expectations/tests/template-param-usage-13.rs +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct BaseIgnoresT { - pub x: ::std::os::raw::c_int, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpUsesU { - pub _base: BaseIgnoresT, - pub usage: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for CrtpUsesU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BaseIgnoresT { + pub x: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseIgnoresT, + pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs index db48fa3be8..77667b454f 100644 --- a/tests/expectations/tests/template-param-usage-15.rs +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BaseUsesT { - pub usage: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for BaseUsesT { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct CrtpIgnoresU { - pub _base: BaseUsesT, - pub y: ::std::os::raw::c_int, -} -impl Default for CrtpIgnoresU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub usage: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpIgnoresU { + pub _base: BaseUsesT, + pub y: ::std::os::raw::c_int, +} +impl Default for CrtpIgnoresU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs index a9ac824b71..4f5987a105 100644 --- a/tests/expectations/tests/template-param-usage-2.rs +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { - pub also: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { + pub also: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs index c5f40e3842..07571dcc45 100644 --- a/tests/expectations/tests/template-param-usage-3.rs +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -1,27 +1,27 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - pub also: T, - pub more: U, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for - UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + pub also: T, + pub more: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for + UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs index dd6886645c..7b8fe9f1ec 100644 --- a/tests/expectations/tests/template-param-usage-4.rs +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -1,20 +1,20 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UsesTemplateParameter { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { - pub x: ::std::os::raw::c_int, -} -impl Default for UsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { + pub x: ::std::os::raw::c_int, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs index 599208d0c3..3efdfac339 100644 --- a/tests/expectations/tests/template-param-usage-5.rs +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectlyUsesTemplateParameter { - pub aliased: IndirectlyUsesTemplateParameter_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectlyUsesTemplateParameter_Aliased = T; -impl Default for IndirectlyUsesTemplateParameter { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectlyUsesTemplateParameter { + pub aliased: IndirectlyUsesTemplateParameter_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectlyUsesTemplateParameter_Aliased = T; +impl Default for IndirectlyUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs index 5f55400cee..3d1378ad98 100644 --- a/tests/expectations/tests/template-param-usage-7.rs +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUseU { - pub t: T, - pub v: V, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUseU { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUseU { + pub t: T, + pub v: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUseU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_char>; diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs index ee81e2b7bf..322c725718 100644 --- a/tests/expectations/tests/template-param-usage-8.rs +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -1,19 +1,19 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct IndirectUsage { - pub member1: IndirectUsage_Typedefed, - pub member2: IndirectUsage_Aliased, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -pub type IndirectUsage_Typedefed = T; -pub type IndirectUsage_Aliased = U; -impl Default for IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectUsage { + pub member1: IndirectUsage_Typedefed, + pub member2: IndirectUsage_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type IndirectUsage_Typedefed = T; +pub type IndirectUsage_Aliased = U; +impl Default for IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs index 02a6bd469e..5f2319c448 100644 --- a/tests/expectations/tests/template-param-usage-9.rs +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -1,24 +1,24 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct DoesNotUse { - pub _address: u8, -} -pub type DoesNotUse_Aliased = T; -pub type DoesNotUse_Typedefed = U; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DoesNotUse_IndirectUsage { - pub member: DoesNotUse_Aliased, - pub another: DoesNotUse_Typedefed, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for DoesNotUse_IndirectUsage { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUse { + pub _address: u8, +} +pub type DoesNotUse_Aliased = T; +pub type DoesNotUse_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUse_IndirectUsage { + pub member: DoesNotUse_Aliased, + pub another: DoesNotUse_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for DoesNotUse_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index cbabaa99ff..682c6db9c1 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -1,279 +1,279 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug)] -pub struct Foo { - pub m_member: T, - pub m_member_ptr: *mut T, - pub m_member_arr: [T; 1usize], - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -extern "C" { - #[link_name = "_Z3bar3FooIiiE"] - pub fn bar(foo: Foo<::std::os::raw::c_int>); -} -#[repr(C)] -#[derive(Debug)] -pub struct D { - pub m_foo: D_MyFoo, -} -pub type D_MyFoo = Foo<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct D_U { - pub m_nested_foo: D_MyFoo, - pub m_baz: Z, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for D_U { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for D { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub prev: *mut T, - pub next: *mut Rooted<*mut ::std::os::raw::c_void>, - pub ptr: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct RootedContainer { - pub root: Rooted<*mut ::std::os::raw::c_void>, -} -#[test] -fn bindgen_test_layout_RootedContainer() { - assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( - "Size of: " , stringify ! ( RootedContainer ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! - ( "Alignment of " , stringify ! ( RootedContainer ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const RootedContainer ) ) . root as * const _ - as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( RootedContainer ) , - "::" , stringify ! ( root ) )); -} -impl Clone for RootedContainer { - fn clone(&self) -> Self { *self } -} -impl Default for RootedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct WithDtor { - pub member: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WithDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; -#[repr(C)] -#[derive(Debug)] -pub struct PODButContainsDtor { - pub member: WithDtorIntFwd, -} -#[test] -fn bindgen_test_layout_PODButContainsDtor() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! - ( "Size of: " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat - ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const PODButContainsDtor ) ) . member as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( PODButContainsDtor ) , - "::" , stringify ! ( member ) )); -} -impl Default for PODButContainsDtor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/**
*/ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Opaque { -} -impl Default for Opaque { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct POD { - pub opaque_member: u32, -} -#[test] -fn bindgen_test_layout_POD() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( POD ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( POD ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( POD ) , "::" , - stringify ! ( opaque_member ) )); -} -impl Clone for POD { - fn clone(&self) -> Self { *self } -} -/** - *
- */ -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedReplaced { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedReplaced { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedBase { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Incomplete { - pub d: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Incomplete { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NestedContainer { - pub c: T, - pub nested: NestedReplaced, - pub inc: Incomplete, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for NestedContainer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct Untemplated { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_Untemplated() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( Untemplated ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( Untemplated ) )); -} -impl Clone for Untemplated { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Templated { - pub m_untemplated: Untemplated, -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructor { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructor { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiable { - pub m_member: ReplacedWithoutDestructor, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiable { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug)] -pub struct ShouldNotBeCopiableAsWell { - pub m_member: ReplacedWithoutDestructorFwd, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ShouldNotBeCopiableAsWell { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -/** - * If the replacement doesn't happen at the parse level the container would be - * copy and the replacement wouldn't, so this wouldn't compile. - * - *
- */ -#[repr(C)] -#[derive(Debug)] -pub struct ReplacedWithoutDestructorFwd { - pub buff: *mut T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for ReplacedWithoutDestructorFwd { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct TemplateWithVar { - pub _address: u8, -} -#[test] -fn __bindgen_test_layout_Foo_instantiation_95() { - assert_eq!(::std::mem::size_of::>() , 24usize , - concat ! ( - "Size of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , 8usize , - concat ! ( - "Alignment of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int> ) )); -} -#[test] -fn __bindgen_test_layout_Rooted_instantiation_106() { - assert_eq!(::std::mem::size_of::>() , - 24usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); - assert_eq!(::std::mem::align_of::>() , - 8usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Rooted<*mut ::std::os::raw::c_void> ) )); -} -#[test] -fn __bindgen_test_layout_WithDtor_instantiation_114() { - assert_eq!(::std::mem::size_of::>() , - 4usize , concat ! ( - "Size of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , - 4usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - WithDtor<::std::os::raw::c_int> ) )); -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug)] +pub struct Foo { + pub m_member: T, + pub m_member_ptr: *mut T, + pub m_member_arr: [T; 1usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + #[link_name = "_Z3bar3FooIiiE"] + pub fn bar(foo: Foo<::std::os::raw::c_int>); +} +#[repr(C)] +#[derive(Debug)] +pub struct D { + pub m_foo: D_MyFoo, +} +pub type D_MyFoo = Foo<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct D_U { + pub m_nested_foo: D_MyFoo, + pub m_baz: Z, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for D_U { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for D { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub prev: *mut T, + pub next: *mut Rooted<*mut ::std::os::raw::c_void>, + pub ptr: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct RootedContainer { + pub root: Rooted<*mut ::std::os::raw::c_void>, +} +#[test] +fn bindgen_test_layout_RootedContainer() { + assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( + "Size of: " , stringify ! ( RootedContainer ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! + ( "Alignment of " , stringify ! ( RootedContainer ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const RootedContainer ) ) . root as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( RootedContainer ) , + "::" , stringify ! ( root ) )); +} +impl Clone for RootedContainer { + fn clone(&self) -> Self { *self } +} +impl Default for RootedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct WithDtor { + pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WithDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; +#[repr(C)] +#[derive(Debug)] +pub struct PODButContainsDtor { + pub member: WithDtorIntFwd, +} +#[test] +fn bindgen_test_layout_PODButContainsDtor() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! + ( "Size of: " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat + ! ( "Alignment of " , stringify ! ( PODButContainsDtor ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const PODButContainsDtor ) ) . member as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( PODButContainsDtor ) , + "::" , stringify ! ( member ) )); +} +impl Default for PODButContainsDtor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/**
*/ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Opaque { +} +impl Default for Opaque { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct POD { + pub opaque_member: u32, +} +#[test] +fn bindgen_test_layout_POD() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( POD ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( POD ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const POD ) ) . opaque_member as * const _ as + usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( POD ) , "::" , + stringify ! ( opaque_member ) )); +} +impl Clone for POD { + fn clone(&self) -> Self { *self } +} +/** + *
+ */ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedReplaced { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedReplaced { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedBase { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedBase { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Incomplete { + pub d: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Incomplete { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedContainer { + pub c: T, + pub nested: NestedReplaced, + pub inc: Incomplete, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for NestedContainer { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Untemplated { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Untemplated() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( Untemplated ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Untemplated ) )); +} +impl Clone for Untemplated { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Templated { + pub m_untemplated: Untemplated, +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructor { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructor { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiable { + pub m_member: ReplacedWithoutDestructor, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiable { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiableAsWell { + pub m_member: ReplacedWithoutDestructorFwd, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ShouldNotBeCopiableAsWell { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +/** + * If the replacement doesn't happen at the parse level the container would be + * copy and the replacement wouldn't, so this wouldn't compile. + * + *
+ */ +#[repr(C)] +#[derive(Debug)] +pub struct ReplacedWithoutDestructorFwd { + pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for ReplacedWithoutDestructorFwd { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct TemplateWithVar { + pub _address: u8, +} +#[test] +fn __bindgen_test_layout_Foo_instantiation_95() { + assert_eq!(::std::mem::size_of::>() , 24usize , + concat ! ( + "Size of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 8usize , + concat ! ( + "Alignment of template specialization: " , stringify ! ( + Foo<::std::os::raw::c_int> ) )); +} +#[test] +fn __bindgen_test_layout_Rooted_instantiation_106() { + assert_eq!(::std::mem::size_of::>() , + 24usize , concat ! ( + "Size of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); + assert_eq!(::std::mem::align_of::>() , + 8usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + Rooted<*mut ::std::os::raw::c_void> ) )); +} +#[test] +fn __bindgen_test_layout_WithDtor_instantiation_114() { + assert_eq!(::std::mem::size_of::>() , + 4usize , concat ! ( + "Size of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + WithDtor<::std::os::raw::c_int> ) )); +} diff --git a/tests/expectations/tests/template_alias.rs b/tests/expectations/tests/template_alias.rs index d0943e94e7..f98d165df8 100644 --- a/tests/expectations/tests/template_alias.rs +++ b/tests/expectations/tests/template_alias.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type JS_detail_Wrapped = T; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JS_Rooted { - pub ptr: JS_detail_Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for JS_Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type JS_detail_Wrapped = T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JS_Rooted { + pub ptr: JS_detail_Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for JS_Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template_alias_namespace.rs b/tests/expectations/tests/template_alias_namespace.rs index ff6a8dc0d2..491bb68cad 100644 --- a/tests/expectations/tests/template_alias_namespace.rs +++ b/tests/expectations/tests/template_alias_namespace.rs @@ -1,29 +1,29 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - pub mod JS { - #[allow(unused_imports)] - use self::super::super::root; - pub mod detail { - #[allow(unused_imports)] - use self::super::super::super::root; - pub type Wrapped = T; - } - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct Rooted { - pub ptr: root::JS::detail::Wrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - } - impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod JS { + #[allow(unused_imports)] + use self::super::super::root; + pub mod detail { + #[allow(unused_imports)] + use self::super::super::super::root; + pub type Wrapped = T; + } + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct Rooted { + pub ptr: root::JS::detail::Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + } + impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + } +} diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index f98100314a..5f6b4c38db 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -1,21 +1,21 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Wrapper { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Wrapper_Wrapped { - pub t: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Wrapper_Wrapped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type Wrapper_Type = Wrapper_Wrapped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Wrapper { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Wrapper_Wrapped { + pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Wrapper_Wrapped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Wrapper_Type = Wrapper_Wrapped; diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs index 4f0c2dc8f7..09c3248621 100644 --- a/tests/expectations/tests/type_alias_partial_template_especialization.rs +++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs @@ -1,16 +1,16 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -pub type MaybeWrapped
= A; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Rooted { - pub ptr: MaybeWrapped, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Rooted { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub type MaybeWrapped = A; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Rooted { + pub ptr: MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/using.rs b/tests/expectations/tests/using.rs index 58a981bcff..44376b93a9 100644 --- a/tests/expectations/tests/using.rs +++ b/tests/expectations/tests/using.rs @@ -1,18 +1,18 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Point { - pub x: T, - pub y: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for Point { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint2D = Point<::std::os::raw::c_int>; -pub type IntVec2D = Point<::std::os::raw::c_int>; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Point { + pub x: T, + pub y: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for Point { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint2D = Point<::std::os::raw::c_int>; +pub type IntVec2D = Point<::std::os::raw::c_int>; diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index f96c4b9254..fa56f04b6d 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -1,33 +1,33 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Default, Copy)] -pub struct UnknownUnits { - pub _address: u8, -} -#[test] -fn bindgen_test_layout_UnknownUnits() { - assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( - "Size of: " , stringify ! ( UnknownUnits ) )); - assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( - "Alignment of " , stringify ! ( UnknownUnits ) )); -} -impl Clone for UnknownUnits { - fn clone(&self) -> Self { *self } -} -pub type Float = f32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PointTyped { - pub x: F, - pub y: F, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for PointTyped { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -pub type IntPoint = PointTyped; +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct UnknownUnits { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_UnknownUnits() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( UnknownUnits ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( UnknownUnits ) )); +} +impl Clone for UnknownUnits { + fn clone(&self) -> Self { *self } +} +pub type Float = f32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PointTyped { + pub x: F, + pub y: F, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for PointTyped { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type IntPoint = PointTyped; diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index 6d4377de4a..a83f02735b 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -1,25 +1,25 @@ -/* automatically generated by rust-bindgen */ - - -#![allow(non_snake_case)] - - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe { - pub foo: ::std::os::raw::c_int, - pub bar: WhitelistMe_Inner, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct WhitelistMe_Inner { - pub bar: T, - _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, -} -impl Default for WhitelistMe_Inner { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for WhitelistMe { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe { + pub foo: ::std::os::raw::c_int, + pub bar: WhitelistMe_Inner, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe_Inner { + pub bar: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for WhitelistMe_Inner { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for WhitelistMe { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} From c2b884ab4c0f31dff75d422e0084296a04ee70fe Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 1 May 2017 20:35:16 -0400 Subject: [PATCH 17/18] added new tests --- .../tests/issue-638-stylo-cannot-find-T-in-this-scope.rs | 2 ++ .../tests/issue-645-cannot-find-type-T-in-this-scope.rs | 1 + .../tests/issue-662-cannot-find-T-in-this-scope.rs | 3 +++ tests/expectations/tests/issue-662-part-2.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs index 4ff0b5bc21..3afaf62d96 100644 --- a/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs +++ b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct RefPtr { pub use_of_t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for RefPtr { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -16,6 +17,7 @@ impl Default for RefPtr { #[derive(Debug, Copy, Clone)] pub struct UsesRefPtrWithAliasedTypeParam { pub member: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type UsesRefPtrWithAliasedTypeParam_V = U; impl Default for UsesRefPtrWithAliasedTypeParam { diff --git a/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs b/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs index 531bce6740..c9695b6958 100644 --- a/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs +++ b/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs @@ -9,6 +9,7 @@ #[derive(Debug, Copy, Clone)] pub struct HasRefPtr { pub refptr_member: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type HasRefPtr_TypedefOfT = T; impl Default for HasRefPtr { diff --git a/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs b/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs index 0c16b23537..4a81f24edb 100644 --- a/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs +++ b/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct RefPtr { pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for RefPtr { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -16,6 +17,7 @@ impl Default for RefPtr { #[derive(Debug, Copy, Clone)] pub struct nsMainThreadPtrHolder { pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsMainThreadPtrHolder { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -24,6 +26,7 @@ impl Default for nsMainThreadPtrHolder { #[derive(Debug, Copy, Clone)] pub struct nsMainThreadPtrHandle { pub mPtr: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsMainThreadPtrHandle { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/issue-662-part-2.rs b/tests/expectations/tests/issue-662-part-2.rs index fa80c5fee2..eb9a34d13d 100644 --- a/tests/expectations/tests/issue-662-part-2.rs +++ b/tests/expectations/tests/issue-662-part-2.rs @@ -9,6 +9,7 @@ #[derive(Debug, Copy, Clone)] pub struct nsMainThreadPtrHolder { pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsMainThreadPtrHolder { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for nsMainThreadPtrHolder { #[derive(Debug, Copy, Clone)] pub struct nsMainThreadPtrHandle { pub mPtr: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsMainThreadPtrHandle { fn default() -> Self { unsafe { ::std::mem::zeroed() } } From 59f496e01e1297f918b3cf548125ec15f4093a01 Mon Sep 17 00:00:00 2001 From: Kowasaki Date: Mon, 17 Apr 2017 02:31:01 -0400 Subject: [PATCH 18/18] [WIP] Generated PhantomData for used generics --- .github/ISSUE_TEMPLATE.md | 26 +- .travis.yml | 8 + Cargo.lock | 55 +- Cargo.toml | 1 - README.md | 234 +--- book/.gitignore | 1 + book/book.toml | 3 + book/src/SUMMARY.md | 20 + book/src/blacklisting.md | 26 + book/src/chapter_1.md | 1 + book/src/command-line-usage.md | 27 + book/src/cpp.md | 27 + book/src/customizing-generated-bindings.md | 28 + book/src/introduction.md | 34 + book/src/library-usage.md | 22 + book/src/nocopy.md | 20 + book/src/opaque.md | 26 + book/src/replacing-types.md | 27 + book/src/requirements.md | 67 + book/src/tutorial-0.md | 12 + book/src/tutorial-1.md | 9 + book/src/tutorial-2.md | 20 + book/src/tutorial-3.md | 58 + book/src/tutorial-4.md | 57 + book/src/tutorial-5.md | 169 +++ book/src/tutorial-6.md | 13 + book/src/whitelisting.md | 31 + ci/deploy-book.sh | 33 + ci/test-book.sh | 10 + src/clang.rs | 40 +- src/codegen/mod.rs | 17 +- src/ir/comp.rs | 52 +- src/ir/context.rs | 88 +- src/ir/function.rs | 6 + src/ir/item.rs | 9 +- src/ir/named.rs | 173 ++- src/ir/traversal.rs | 10 - src/ir/ty.rs | 1 + src/lib.rs | 66 +- src/main.rs | 1 - src/options.rs | 24 +- .../tests/anonymous-template-types.rs | 2 + tests/expectations/tests/class_nested.rs | 3 + tests/expectations/tests/class_with_dtor.rs | 1 + tests/expectations/tests/const_tparam.rs | 1 + .../tests/default-template-parameter.rs | 2 + .../tests/forward-declaration-autoptr.rs | 5 +- .../forward-inherit-struct-with-fields.rs | 2 + .../tests/forward_declared_complex_types.rs | 12 +- tests/expectations/tests/inherit_named.rs | 1 + ...issue-584-stylo-template-analysis-panic.rs | 1 + ...e-638-stylo-cannot-find-T-in-this-scope.rs | 2 + .../tests/issue-639-typedef-anon-field.rs | 81 ++ .../tests/issue-643-inner-struct.rs | 108 ++ ...ue-645-cannot-find-type-T-in-this-scope.rs | 17 + .../tests/issue-654-struct-fn-collision.rs | 14 + .../issue-662-cannot-find-T-in-this-scope.rs | 33 + tests/expectations/tests/issue-662-part-2.rs | 25 + tests/expectations/tests/issue-674-1.rs | 46 + tests/expectations/tests/issue-674-2.rs | 69 ++ tests/expectations/tests/issue-674-3.rs | 60 + .../tests/issue-677-nested-ns-specifier.rs | 20 + tests/expectations/tests/layout_array.rs | 4 +- tests/expectations/tests/namespace.rs | 2 + tests/expectations/tests/nsStyleAutoArray.rs | 2 + .../tests/replace_template_alias.rs | 1 + tests/expectations/tests/replaces_double.rs | 1 + ...ame_struct_name_in_different_namespaces.rs | 4 +- .../tests/template-param-usage-0.rs | 1 + .../tests/template-param-usage-10.rs | 4 + .../tests/template-param-usage-12.rs | 2 + .../tests/template-param-usage-13.rs | 1 + .../tests/template-param-usage-15.rs | 1 + .../tests/template-param-usage-2.rs | 2 + .../tests/template-param-usage-3.rs | 3 + .../tests/template-param-usage-4.rs | 1 + .../tests/template-param-usage-5.rs | 1 + .../tests/template-param-usage-7.rs | 2 + .../tests/template-param-usage-8.rs | 2 + .../tests/template-param-usage-9.rs | 2 + tests/expectations/tests/template.rs | 12 + tests/expectations/tests/template_alias.rs | 1 + .../tests/template_alias_namespace.rs | 1 + .../template_typedef_transitive_param.rs | 1 + .../test_multiple_header_calls_in_builder.rs | 17 + ..._alias_partial_template_especialization.rs | 1 + tests/expectations/tests/using.rs | 1 + tests/expectations/tests/what_is_going_on.rs | 1 + tests/expectations/tests/whitelist_basic.rs | 2 + .../headers/issue-639-typedef-anon-field.hpp | 15 + tests/headers/issue-643-inner-struct.h | 13 + ...e-645-cannot-find-type-T-in-this-scope.hpp | 9 + tests/headers/issue-654-struct-fn-collision.h | 2 + .../issue-662-cannot-find-T-in-this-scope.hpp | 7 + tests/headers/issue-662-part-2.hpp | 11 + tests/headers/issue-674-1.hpp | 8 + tests/headers/issue-674-2.hpp | 15 + tests/headers/issue-674-3.hpp | 11 + .../headers/issue-677-nested-ns-specifier.hpp | 5 + tests/stylo_sanity.rs | 1095 +++++++++-------- tests/test-one.sh | 17 +- tests/tests.rs | 26 + 102 files changed, 2415 insertions(+), 949 deletions(-) create mode 100644 book/.gitignore create mode 100644 book/book.toml create mode 100644 book/src/SUMMARY.md create mode 100644 book/src/blacklisting.md create mode 100644 book/src/chapter_1.md create mode 100644 book/src/command-line-usage.md create mode 100644 book/src/cpp.md create mode 100644 book/src/customizing-generated-bindings.md create mode 100644 book/src/introduction.md create mode 100644 book/src/library-usage.md create mode 100644 book/src/nocopy.md create mode 100644 book/src/opaque.md create mode 100644 book/src/replacing-types.md create mode 100644 book/src/requirements.md create mode 100644 book/src/tutorial-0.md create mode 100644 book/src/tutorial-1.md create mode 100644 book/src/tutorial-2.md create mode 100644 book/src/tutorial-3.md create mode 100644 book/src/tutorial-4.md create mode 100644 book/src/tutorial-5.md create mode 100644 book/src/tutorial-6.md create mode 100644 book/src/whitelisting.md create mode 100755 ci/deploy-book.sh create mode 100755 ci/test-book.sh create mode 100644 tests/expectations/tests/issue-639-typedef-anon-field.rs create mode 100644 tests/expectations/tests/issue-643-inner-struct.rs create mode 100644 tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs create mode 100644 tests/expectations/tests/issue-654-struct-fn-collision.rs create mode 100644 tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs create mode 100644 tests/expectations/tests/issue-662-part-2.rs create mode 100644 tests/expectations/tests/issue-674-1.rs create mode 100644 tests/expectations/tests/issue-674-2.rs create mode 100644 tests/expectations/tests/issue-674-3.rs create mode 100644 tests/expectations/tests/issue-677-nested-ns-specifier.rs create mode 100644 tests/expectations/tests/test_multiple_header_calls_in_builder.rs create mode 100644 tests/headers/issue-639-typedef-anon-field.hpp create mode 100644 tests/headers/issue-643-inner-struct.h create mode 100644 tests/headers/issue-645-cannot-find-type-T-in-this-scope.hpp create mode 100644 tests/headers/issue-654-struct-fn-collision.h create mode 100644 tests/headers/issue-662-cannot-find-T-in-this-scope.hpp create mode 100644 tests/headers/issue-662-part-2.hpp create mode 100644 tests/headers/issue-674-1.hpp create mode 100644 tests/headers/issue-674-2.hpp create mode 100644 tests/headers/issue-674-3.hpp create mode 100644 tests/headers/issue-677-nested-ns-specifier.hpp diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 68dfb68e13..33b65a200f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,14 +1,12 @@ ### Input C/C++ Header ```C++ -// Insert your (minimal) C/C++ header here +// Insert your (minimal) C/C++ header here. ``` ### Bindgen Invokation - ```Rust bindgen::Builder::default() @@ -17,26 +15,22 @@ bindgen::Builder::default() .unwrap() ``` -OR +or ``` $ bindgen input.h --whatever --flags ``` ---> - ### Actual Results - - ### Expected Results ### `RUST_LOG=bindgen` Output +
+ ``` -Insert debug logging when running bindgen with the RUST_LOG=bindgen environment +Insert debug logging when running bindgen with the `RUST_LOG=bindgen` environment variable set. ``` + +
diff --git a/.travis.yml b/.travis.yml index 2def8e3af8..f66c7d3684 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,14 @@ script: # - ./ci/assert-rustfmt.sh - BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/assert-docs.sh - BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/test.sh + - ./ci/test-book.sh + +after_success: + - test "$TRAVIS_PULL_REQUEST" == "false" && + test "$TRAVIS_BRANCH" == "master" && + test "$BINDGEN_FEATURES" == "" && + test "$LLVM_VERSION" == "3.9.0" && + ./ci/deploy-book.sh notifications: webhooks: http://build.servo.org:54856/travis diff --git a/Cargo.lock b/Cargo.lock index 37c8065ec0..e0fddcd7dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,16 +5,15 @@ dependencies = [ "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -46,7 +45,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -70,18 +69,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clang-sys" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clap" -version = "2.23.2" +version = "2.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -134,12 +133,12 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -148,7 +147,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "target_build_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -163,7 +162,7 @@ name = "memchr" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -235,7 +234,7 @@ name = "rand" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -257,12 +256,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-serialize" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "0.9.13" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -273,7 +272,7 @@ dependencies = [ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -305,8 +304,8 @@ name = "syntex_errors" version = "0.58.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -317,7 +316,7 @@ name = "syntex_pos" version = "0.58.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,7 +326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -358,7 +357,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -368,7 +367,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -436,16 +435,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" -"checksum clang-sys 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "905d957c19424e25e4bd359e0009cbdecfd765f2632fd8d2ba1b576fadd22dc2" -"checksum clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf1114886d7cde2d6448517161d7db8d681a9a1c09f7d210f0b0864e48195f6" +"checksum clang-sys 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f048fc517ae55a21e25d8081764fe5795653ac16c63b45e99755f2a6c0378b31" +"checksum clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f57e9b63057a545ad2ecd773ea61e49422ed1b1d63d74d5da5ecaee55b3396cd" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61b8421c7a4648c391611625d56fdd5c7567da05af1be655fd8cacc643abb3" -"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" +"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502" "checksum libloading 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0a020ac941774eb37e9d13d418c37b522e76899bfc4e7b1a600d529a53f83a66" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" @@ -460,8 +459,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" -"checksum serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)" = "231dfd55909400769e437326cfb4af8bec97c3dd56ab3d02df8ef5c7e00f179b" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" "checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" diff --git a/Cargo.toml b/Cargo.toml index 09f4e787d0..7818096dd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,6 @@ cexpr = "0.2" cfg-if = "0.1.0" clang-sys = { version = "0.15", features = ["runtime", "clang_3_9"] } lazy_static = "0.2.1" -rustc-serialize = "0.3.19" syntex_syntax = "0.58" regex = "0.2" # This kinda sucks: https://github.com/rust-lang/cargo/issues/1982 diff --git a/README.md b/README.md index 9c219ef566..055ac7a7f7 100644 --- a/README.md +++ b/README.md @@ -1,227 +1,45 @@ # `bindgen` -Automatically generates Rust FFI bindings to C and C++ libraries. +**`bindgen` automatically generates Rust FFI bindings to C and C++ libraries.** - - +For example, given the C header `cool.h`: +```c +typedef struct CoolStruct { + int x; + int y; +} CoolStruct; -- [Usage](#usage) - - [Requirements](#requirements) - - [Installing Clang 3.9](#installing-clang-39) - - [Windows](#windows) - - [OSX](#osx) - - [Debian-based Linuxes](#debian-based-linuxes) - - [Arch](#arch) - - [From source](#from-source) - - [Library usage with `build.rs`](#library-usage-with-buildrs) - - [`build.rs` Tutorial](#buildrs-tutorial) - - [Simple Example: `./bindgen-integration`](#simple-example-bindgen-integration) - - [Real World Example: Stylo](#real-world-example-stylo) - - [Command Line Usage](#command-line-usage) - - [C++](#c) - - [Annotations](#annotations) - - [`opaque`](#opaque) - - [`hide`](#hide) - - [`replaces`](#replaces) - - [`nocopy`](#nocopy) - - - -## Usage - -### Requirements - -It is recommended to use Clang 3.9 or greater, however `bindgen` can run with -older Clangs with some features disabled. - -#### Installing Clang 3.9 - -##### Windows - -Download and install the official pre-built binary from -[LLVM download page](http://releases.llvm.org/download.html). - -##### OSX - -If you use Homebrew: - -``` -$ brew install llvm -``` - -If you use MacPorts: - -``` -$ port install clang-3.9 -``` - -##### Debian-based Linuxes - +void cool_function(int i, char c, CoolStruct* cs); ``` -# apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9 -``` - -Ubuntu 16.10 provides the necessary packages directly. If you are using older -version of Ubuntu or other Debian-based distros, you may need to add the LLVM -repos to get version 3.9. See http://apt.llvm.org/. - -##### Arch - -``` -# pacman -S clang -``` - -##### From source - -If your package manager doesn't yet offer Clang 3.9, you'll need to build from -source. For that, follow the instructions -[here](http://clang.llvm.org/get_started.html). - -Those instructions list optional steps. For bindgen: - -* Checkout and build clang -* Checkout and build the extra-clang-tools -* Checkout and build the compiler-rt -* You do not need to checkout or build libcxx - -### Library usage with `build.rs` - -💡 This is the recommended way to use `bindgen`. 💡 - -#### `build.rs` Tutorial - -[Here is a step-by-step tutorial for generating FFI bindings to the `bzip2` C library.][tutorial] - -[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html - -#### Simple Example: `./bindgen-integration` - -The [`./bindgen-integration`][integration] directory has an example crate that -generates FFI bindings in `build.rs` and can be used a template for new -projects. - -[integration]: ./bindgen-integration -#### Real World Example: Stylo - -A real world example is [the Stylo build script][stylo-script] used for -integrating Servo's layout system into Gecko. - -[stylo-script]: https://github.com/servo/servo/blob/master/components/style/build_gecko.rs - -In `Cargo.toml`: - -```toml -[package] -# ... -build = "build.rs" - -[build-dependencies] -bindgen = "0.20" -``` - -In `build.rs`: +`bindgen` produces Rust FFI code allowing you to call into the `cool` library's +functions and use its types: ```rust -extern crate bindgen; +/* automatically generated by rust-bindgen */ -use std::env; -use std::path::Path; - -fn main() { - let out_dir = env::var("OUT_DIR").unwrap(); - let _ = bindgen::builder() - .header("example.h") - .use_core() - .generate().unwrap() - .write_to_file(Path::new(&out_dir).join("example.rs")); +#[repr(C)] +pub struct CoolStruct { + pub x: ::std::os::raw::c_int, + pub y: ::std::os::raw::c_int, } -``` - -In `src/main.rs`: - -```rust -include!(concat!(env!("OUT_DIR"), "/example.rs")); -``` - -### Command Line Usage - -``` -$ cargo install bindgen -``` - -There are a few options documented when running `bindgen --help`. Bindgen is installed to `~/.cargo/bin`. You have to add that directory to your path to use `bindgen`. -### C++ - -`bindgen` can handle most C++ features, but not all of them (C++ is hard!) - -Notable C++ features that are unsupported or only partially supported: - -* Partial template specialization -* Traits templates -* SFINAE -* Instantiating new template specializations - -When passing in header files, the file will automatically be treated as C++ if -it ends in ``.hpp``. If it doesn't, ``-x c++`` can be used to force C++ mode. - -You must use whitelisting when working with C++ to avoid pulling in all of the -`std::*` types, some of which `bindgen` cannot handle. Additionally, you may -want to blacklist other types that `bindgen` stumbles on, or make `bindgen` -treat certain types as opaque. - -### Annotations - -The translation of classes, structs, enums, and typedefs can be adjusted using -annotations. Annotations are specifically formatted html tags inside doxygen -style comments. - -#### `opaque` - -The `opaque` annotation instructs bindgen to ignore all fields defined in -a struct/class. - -```cpp -///
-``` - -#### `hide` - -The `hide` annotation instructs bindgen to ignore the struct/class/field/enum -completely. - -```cpp -///
+extern "C" { + pub fn cool_function(i: ::std::os::raw::c_int, + c: ::std::os::raw::c_char, + cs: *mut CoolStruct); +} ``` -#### `replaces` +## Users Guide -The `replaces` annotation can be used to use a type as a replacement for other -(presumably more complex) type. This is used in Stylo to generate bindings for -structures that for multiple reasons are too complex for bindgen to understand. +[📚 Read the `bindgen` users guide here! 📚](https://servo.github.io/rust-bindgen) -For example, in a C++ header: - -```cpp -/** - *
- */ -template -class nsTArray_Simple { - T* mBuffer; -public: - // The existence of a destructor here prevents bindgen from deriving the Clone - // trait via a simple memory copy. - ~nsTArray_Simple() {}; -}; -``` +## API Reference -That way, after code generation, the bindings for the `nsTArray` type are -the ones that would be generated for `nsTArray_Simple`. +[API reference documentation is on docs.rs](https://docs.rs/bindgen) -#### `nocopy` +## Contributing -The `nocopy` annotation is used to prevent bindgen to autoderive the `Copy` -and `Clone` traits for a type. +[See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md) diff --git a/book/.gitignore b/book/.gitignore new file mode 100644 index 0000000000..7585238efe --- /dev/null +++ b/book/.gitignore @@ -0,0 +1 @@ +book diff --git a/book/book.toml b/book/book.toml new file mode 100644 index 0000000000..e94e304621 --- /dev/null +++ b/book/book.toml @@ -0,0 +1,3 @@ +title = "The `bindgen` User Guide" +author = "The Servo project developers" +description = "`bindgen` automatically generates Rust FFI bindings to C and C++ libraries." diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md new file mode 100644 index 0000000000..1a1818f804 --- /dev/null +++ b/book/src/SUMMARY.md @@ -0,0 +1,20 @@ +# Summary + +- [Introduction](./introduction.md) +- [Requirements](./requirements.md) +- [Library Usage with `build.rs`](./library-usage.md) + - [Tutorial](./tutorial-0.md) + - [Add `bindgen` as a Build Dependency](./tutorial-1.md) + - [Create a `wrapper.h` Header](./tutorial-2.md) + - [Create a `build.rs` File](./tutorial-3.md) + - [Include the Generated Bindings in `src/lib.rs`](./tutorial-4.md) + - [Write a Sanity Test](./tutorial-5.md) + - [Publish Your Crate!](./tutorial-6.md) +- [Command Line Usage](./command-line-usage.md) +- [Customizing the Generated Bindings](./customizing-generated-bindings.md) + - [Whitelisting](./whitelisting.md) + - [Blacklisting](./blacklisting.md) + - [Treating a Type as an Opaque Blob of Bytes](./opaque.md) + - [Replacing One Type with Another](./replacing-types.md) + - [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md) +- [Generating Bindings to C++](./cpp.md) diff --git a/book/src/blacklisting.md b/book/src/blacklisting.md new file mode 100644 index 0000000000..990947abaf --- /dev/null +++ b/book/src/blacklisting.md @@ -0,0 +1,26 @@ +# Blacklisting + +If you need to provide your own custom translation of some type (for example, +because you need to wrap one of its fields in an `UnsafeCell`), you can +explicitly blacklist generation of its definition. Uses of the blacklisted type +will still appear in other types' definitions. (If you don't want the type to +appear in the bindings at +all, [make it opaque](./opaque.html) instead of +blacklisting it.) + +### Library + +* [`bindgen::Builder::hide_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.hide_type) + +### Command Line + +* `--blacklist-type ` + +### Annotations + +```cpp +///
+class Foo { + // ... +}; +``` diff --git a/book/src/chapter_1.md b/book/src/chapter_1.md new file mode 100644 index 0000000000..b743fda354 --- /dev/null +++ b/book/src/chapter_1.md @@ -0,0 +1 @@ +# Chapter 1 diff --git a/book/src/command-line-usage.md b/book/src/command-line-usage.md new file mode 100644 index 0000000000..d90eb442b8 --- /dev/null +++ b/book/src/command-line-usage.md @@ -0,0 +1,27 @@ +# Command Line Usage + +Install the `bindgen` executable with `cargo`: + +```bash +$ cargo install bindgen +``` + +The `bindgen` executable is installed to `~/.cargo/bin`. You have to add that +directory to your `$PATH` to use `bindgen`. + +`bindgen` takes the path to an input C or C++ header file, and optionally an +output file path for the generated bindings. If the output file path is not +supplied, the bindings are printed to `stdout`. + +If we wanted to generated Rust FFI bindings from a C header named `input.h` and +put them in the `bindings.rs` file, we would invoke `bindgen` like this: + +```bash +$ bindgen input.h -o bindings.rs +``` + +For more details, pass the `--help` flag: + +```bash +$ bindgen --help +``` diff --git a/book/src/cpp.md b/book/src/cpp.md new file mode 100644 index 0000000000..e0fbecb752 --- /dev/null +++ b/book/src/cpp.md @@ -0,0 +1,27 @@ +# Generating Bindings to C++ + +`bindgen` can handle a surprising number of C++ features, but not all of +them. When `bindgen` can't translate some C++ construct into Rust, it usually +comes down to one of two things: + +1. Rust has no equivalent language feature +2. C++ is *hard!* + +Notable C++ features that are unsupported or only partially supported, and for +which `bindgen` *should* generate opaque blobs whenever it finds an occurrence +of them in a type it is generating bindings for: + +* Template specialization +* Partial template specialization +* Traits templates +* SFINAE + +When passing in header files, the file will automatically be treated as C++ if +it ends in `.hpp`. If it doesn't, adding `-x=c++` clang args can be used to +force C++ mode. You probably also want to use `-std=c++14` or similar clang args +as well. + +You pretty much **must** use [whitelisting](./whitelisting.html) when working +with C++ to avoid pulling in all of the `std::*` types, many of which `bindgen` +cannot handle. Additionally, you may want to mark other types +as [opaque](./opaque.html) that `bindgen` stumbles on. diff --git a/book/src/customizing-generated-bindings.md b/book/src/customizing-generated-bindings.md new file mode 100644 index 0000000000..aaaaebea6a --- /dev/null +++ b/book/src/customizing-generated-bindings.md @@ -0,0 +1,28 @@ +# Customizing the Generated Bindings + +The translation of classes, structs, enums, and typedefs can be adjusted in a +few ways: + +1. By using the `bindgen::Builder`'s configuration methods, when using `bindgen` + as a library. + +2. By passing extra flags and options to the `bindgen` executable. + +3. By adding an annotation comment to the C/C++ source code. Annotations are + specially formatted HTML tags inside doxygen style comments: + + * For single line comments: + ```c + ///
+ ``` + + * For multi-line comments: + ```c + /** + *
+ */ + ``` + +We'll leave the nitty-gritty details to +the [docs.rs API reference](https://docs.rs/bindgen) and `bindgen --help`, but +provide higher level concept documentation here. diff --git a/book/src/introduction.md b/book/src/introduction.md new file mode 100644 index 0000000000..4c5fbd49ac --- /dev/null +++ b/book/src/introduction.md @@ -0,0 +1,34 @@ +# Introduction + +**[`bindgen`](https://github.com/servo/rust-bindgen) automatically generates Rust +FFI bindings to C and C++ libraries.** + +For example, given the C header `cool.h`: + +```c +typedef struct CoolStruct { + int x; + int y; +} CoolStruct; + +void cool_function(int i, char c, CoolStruct* cs); +``` + +`bindgen` produces Rust FFI code allowing you to call into the `cool` library's +functions and use its types: + +```rust +/* automatically generated by rust-bindgen */ + +#[repr(C)] +pub struct CoolStruct { + pub x: ::std::os::raw::c_int, + pub y: ::std::os::raw::c_int, +} + +extern "C" { + pub fn cool_function(i: ::std::os::raw::c_int, + c: ::std::os::raw::c_char, + cs: *mut CoolStruct); +} +``` diff --git a/book/src/library-usage.md b/book/src/library-usage.md new file mode 100644 index 0000000000..35b53fe437 --- /dev/null +++ b/book/src/library-usage.md @@ -0,0 +1,22 @@ +# Library Usage with `build.rs` + +💡 This is the recommended way to use `bindgen`. 💡 + +Often times C and C++ headers will have platform- and architecture-specific +`#ifdef`s that affect the shape of the Rust FFI bindings we need to create to +interface Rust code with the outside world. By using `bindgen` as a library +inside your `build.rs`, you can generate bindings for the current target +on-the-fly. Otherwise, you would need to generate and maintain +`x86_64-unknown-linux-gnu-bindings.rs`, `x86_64-apple-darwin-bindings.rs`, +etc... separate bindings files for each of your supported targets, which can be +a huge pain. The downside is that everyone building your crate also needs +`libclang` available to run `bindgen`. + +## Library API Documentation + +[📚 There is complete API reference documentation on docs.rs 📚](https://docs.rs/bindgen) + +## Tutorial + +The next section contains a detailed, step-by-step tutorial for using `bindgen` +as a library inside `build.rs`. diff --git a/book/src/nocopy.md b/book/src/nocopy.md new file mode 100644 index 0000000000..893f0932b6 --- /dev/null +++ b/book/src/nocopy.md @@ -0,0 +1,20 @@ +# Preventing the Derivation of `Copy` and `Clone` + +`bindgen` will attempt to derive the `Copy` and `Clone` traits on a best-effort +basis. Sometimes, it might not understand that although adding `#[derive(Copy, +Clone)]` to a translated type definition will compile, it still shouldn't do +that for reasons it can't know. In these cases, the `nocopy` annotation can be +used to prevent bindgen to autoderive the `Copy` and `Clone` traits for a type. + +```c +/** + * Although bindgen can't know, this struct is not safe to move because pthread + * mutexes can't move in memory! + * + *
+ */ +struct MyMutexWrapper { + pthread_mutex_t raw; + // ... +}; +``` diff --git a/book/src/opaque.md b/book/src/opaque.md new file mode 100644 index 0000000000..e1bf600cec --- /dev/null +++ b/book/src/opaque.md @@ -0,0 +1,26 @@ +# Treating a Type as an Opaque Blob of Bytes + +Sometimes a type definition is simply not translatable to Rust, for example it +uses +[C++'s SFINAE](https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error) for +which Rust has no equivalent. In these cases, it is best to treat all +occurrences of the type as an opaque blob of bytes with a size and +alignment. `bindgen` will attempt to detect such cases and do this +automatically, but other times it needs some explicit help from you. + +### Library + +* [`bindgen::Builder::opaque_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.opaque_type) + +### Command Line + +* `--opaque-type ` + +### Annotation + +```cpp +///
+class Foo { + // ... +}; +``` diff --git a/book/src/replacing-types.md b/book/src/replacing-types.md new file mode 100644 index 0000000000..7426d2ea55 --- /dev/null +++ b/book/src/replacing-types.md @@ -0,0 +1,27 @@ +# Replacing One Type with Another + +The `replaces` annotation can be used to use a type as a replacement for other +(presumably more complex) type. This is used in Stylo to generate bindings for +structures that for multiple reasons are too complex for bindgen to understand. + +For example, in a C++ header: + +```cpp +/** + *
+ */ +template +class nsTArray_Simple { + T* mBuffer; +public: + // The existence of a destructor here prevents bindgen from deriving the Clone + // trait via a simple memory copy. + ~nsTArray_Simple() {}; +}; +``` + +That way, after code generation, the bindings for the `nsTArray` type are +the ones that would be generated for `nsTArray_Simple`. + +Replacing is only available as an annotation. To replace a C or C++ definition +with a Rust definition, use [blacklisting](./blacklisting.html). diff --git a/book/src/requirements.md b/book/src/requirements.md new file mode 100644 index 0000000000..82da999144 --- /dev/null +++ b/book/src/requirements.md @@ -0,0 +1,67 @@ +# Requirements + +This page lists the requirements for running `bindgen` and how to get them. + +## Clang + +`bindgen` leverages `libclang` to preprocess, parse, and type check C and C++ +header files. + +It is recommended to use Clang 3.9 or greater, however `bindgen` can run with +older Clangs with some features disabled. + +* **If you are generating bindings to C,** 3.7 and 3.8 will probably work OK for +you. + +* **If you are generating bindings to C++,** you almost definitely want 3.9 or +greater. + +### Installing Clang 3.9 + +#### Windows + +Download and install the official pre-built binary from +[LLVM download page](http://releases.llvm.org/download.html). + +#### macOS + +If you use Homebrew: + +```bash +$ brew install llvm@3.9 +``` + +If you use MacPorts: + +```bash +$ port install clang-3.9 +``` + +#### Debian-based Linuxes + +```bash +# apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9 +``` + +Ubuntu 16.10 provides the necessary packages directly. If you are using older +version of Ubuntu or other Debian-based distros, you may need to add the LLVM +repos to get version 3.9. See http://apt.llvm.org/. + +#### Arch + +```bash +# pacman -S clang +``` + +#### From source + +If your package manager doesn't yet offer Clang 3.9, you'll need to build from +source. For that, follow the +instructions [here](http://clang.llvm.org/get_started.html). + +Those instructions list optional steps. For `bindgen`: + +* Checkout and build clang +* Checkout and build the extra-clang-tools +* You do not need to checkout or build compiler-rt +* You do not need to checkout or build libcxx diff --git a/book/src/tutorial-0.md b/book/src/tutorial-0.md new file mode 100644 index 0000000000..adb8430820 --- /dev/null +++ b/book/src/tutorial-0.md @@ -0,0 +1,12 @@ +# Tutorial + +The following tutorial is adapted from [this blog post][tutorial]. + +What follows is a whirlwind introductory tutorial to using `bindgen` from inside +`build.rs`. We'll generate bindings to `bzip2` (which is available on most +systems) on-the-fly. + +[**TL;DR?** The full tutorial code is available here.][example] + +[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html +[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys diff --git a/book/src/tutorial-1.md b/book/src/tutorial-1.md new file mode 100644 index 0000000000..1b10950616 --- /dev/null +++ b/book/src/tutorial-1.md @@ -0,0 +1,9 @@ +# Add `bindgen` as a Build Dependency + +Declare a build-time dependency on `bindgen` by adding it to the +`[build-dependencies]` section of our crate's `Cargo.toml` metadata file: + +```toml +[build-dependencies] +bindgen = "0.23" +``` diff --git a/book/src/tutorial-2.md b/book/src/tutorial-2.md new file mode 100644 index 0000000000..e1e88811b0 --- /dev/null +++ b/book/src/tutorial-2.md @@ -0,0 +1,20 @@ +# Create a `wrapper.h` Header + +The `wrapper.h` file will include all the various headers containing +declarations of structs and functions we would like bindings for. In the +particular case of `bzip2`, this is pretty easy since the entire public API is +contained in a single header. For a project like [SpiderMonkey][spidermonkey], +where the public API is split across multiple header files and grouped by +functionality, we'd want to include all those headers we want to bind to in this +single `wrapper.h` entry point for `bindgen`. + +Here is our `wrapper.h`: + +```c +#include +``` + +This is also where we would add any [replacement types](./replacing-types.html), +if we were using some. + +[spidermonkey]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine diff --git a/book/src/tutorial-3.md b/book/src/tutorial-3.md new file mode 100644 index 0000000000..7c081a4d3d --- /dev/null +++ b/book/src/tutorial-3.md @@ -0,0 +1,58 @@ +# Create a `build.rs` File + +First, we have to tell `cargo` that we have a `build.rs` script by adding +another line to the `Cargo.toml`: + +```toml +[package] +build = "build.rs" +``` + +Second, we create the `build.rs` file in our crate's root. This file is compiled +and executed before the rest of the crate is built, and can be used to generate +code at compile time. And of course in our case, we will be generating Rust FFI +bindings to `bzip2` at compile time. The resulting bindings will be written to +`$OUT_DIR/bindings.rs` where `$OUT_DIR` is chosen by `cargo` and is something +like `./target/debug/build/libbindgen-tutorial-bzip2-sys-afc7747d7eafd720/out/`. + +```rust,ignore +extern crate bindgen; + +use std::env; +use std::path::PathBuf; + +fn main() { + // Tell cargo to tell rustc to link the system bzip2 + // shared library. + println!("cargo:rustc-link-lib=bz2"); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings = bindgen::Builder::default() + // Do not generate unstable Rust code that + // requires a nightly rustc and enabling + // unstable features. + .no_unstable_rust() + // The input header we would like to generate + // bindings for. + .header("wrapper.h") + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} +``` + +Now, when we run `cargo build`, our bindings to `bzip2` are generated on the +fly! + +[There's more info about `build.rs` files in the crates.io documentation.][build-rs] + +[build-rs]: http://doc.crates.io/build-script.html diff --git a/book/src/tutorial-4.md b/book/src/tutorial-4.md new file mode 100644 index 0000000000..42aa92fd00 --- /dev/null +++ b/book/src/tutorial-4.md @@ -0,0 +1,57 @@ +# Include the Generated Bindings in `src/lib.rs` + +We can use the `include!` macro to dump our generated bindings right into our +crate's main entry point, `src/lib.rs`: + +```rust,ignore +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +``` + +Because `bzip2`'s symbols do not follow Rust's style conventions, we suppress a +bunch of warnings with a few `#![allow(...)]` pragmas. + +We can run `cargo build` again to check that the bindings themselves compile: + +```bash +$ cargo build + Compiling libbindgen-tutorial-bzip2-sys v0.1.0 + Finished debug [unoptimized + debuginfo] target(s) in 62.8 secs +``` + +And we can run `cargo test` to verify that the layout, size, and alignment of +our generated Rust FFI structs match what `bindgen` thinks they should be: + +```bash +$ cargo test + Compiling libbindgen-tutorial-bzip2-sys v0.1.0 + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/bzip2_sys-10413fc2af207810 + +running 14 tests +test bindgen_test_layout___darwin_pthread_handler_rec ... ok +test bindgen_test_layout___sFILE ... ok +test bindgen_test_layout___sbuf ... ok +test bindgen_test_layout__bindgen_ty_1 ... ok +test bindgen_test_layout__bindgen_ty_2 ... ok +test bindgen_test_layout__opaque_pthread_attr_t ... ok +test bindgen_test_layout__opaque_pthread_cond_t ... ok +test bindgen_test_layout__opaque_pthread_mutex_t ... ok +test bindgen_test_layout__opaque_pthread_condattr_t ... ok +test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok +test bindgen_test_layout__opaque_pthread_once_t ... ok +test bindgen_test_layout__opaque_pthread_rwlock_t ... ok +test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok +test bindgen_test_layout__opaque_pthread_t ... ok + +test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests libbindgen-tutorial-bzip2-sys + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` diff --git a/book/src/tutorial-5.md b/book/src/tutorial-5.md new file mode 100644 index 0000000000..7ff5ffb920 --- /dev/null +++ b/book/src/tutorial-5.md @@ -0,0 +1,169 @@ +# Write a Sanity Test + +Finally, to tie everything together, let's write a sanity test that round trips +some text through compression and decompression, and then asserts that it came +back out the same as it went in. This is a little wordy using the raw FFI +bindings, but hopefully we wouldn't usually ask people to do this, we'd provide +a nice Rust-y API on top of the raw FFI bindings for them. However, since this +is for testing the bindings directly, our sanity test will use the bindings +directly. + +The test data I'm round tripping are some Futurama quotes I got off the internet +and put in the `futurama-quotes.txt` file, which is read into a `&'static str` +at compile time via the `include_str!("../futurama-quotes.txt")` macro +invocation. + +Without further ado, here is the test, which should be appended to the bottom of +our `src/lib.rs` file: + +```rust +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + + #[test] + fn round_trip_compression_decompression() { + unsafe { + let input = include_str!("../futurama-quotes.txt").as_bytes(); + let mut compressed_output: Vec = vec![0; input.len()]; + let mut decompressed_output: Vec = vec![0; input.len()]; + + // Construct a compression stream. + let mut stream: bz_stream = mem::zeroed(); + let result = BZ2_bzCompressInit(&mut stream as *mut _, + 1, // 1 x 100000 block size + 4, // verbosity (4 = most verbose) + 0); // default work factor + match result { + r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"), + r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"), + r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"), + r if r == (BZ_OK as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + // Compress `input` into `compressed_output`. + stream.next_in = input.as_ptr() as *mut _; + stream.avail_in = input.len() as _; + stream.next_out = compressed_output.as_mut_ptr() as *mut _; + stream.avail_out = compressed_output.len() as _; + let result = BZ2_bzCompress(&mut stream as *mut _, BZ_FINISH as _); + match result { + r if r == (BZ_RUN_OK as _) => panic!("BZ_RUN_OK"), + r if r == (BZ_FLUSH_OK as _) => panic!("BZ_FLUSH_OK"), + r if r == (BZ_FINISH_OK as _) => panic!("BZ_FINISH_OK"), + r if r == (BZ_SEQUENCE_ERROR as _) => panic!("BZ_SEQUENCE_ERROR"), + r if r == (BZ_STREAM_END as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + // Finish the compression stream. + let result = BZ2_bzCompressEnd(&mut stream as *mut _); + match result { + r if r == (BZ_PARAM_ERROR as _) => panic!(BZ_PARAM_ERROR), + r if r == (BZ_OK as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + // Construct a decompression stream. + let mut stream: bz_stream = mem::zeroed(); + let result = BZ2_bzDecompressInit(&mut stream as *mut _, + 4, // verbosity (4 = most verbose) + 0); // default small factor + match result { + r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"), + r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"), + r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"), + r if r == (BZ_OK as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + // Decompress `compressed_output` into `decompressed_output`. + stream.next_in = compressed_output.as_ptr() as *mut _; + stream.avail_in = compressed_output.len() as _; + stream.next_out = decompressed_output.as_mut_ptr() as *mut _; + stream.avail_out = decompressed_output.len() as _; + let result = BZ2_bzDecompress(&mut stream as *mut _); + match result { + r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"), + r if r == (BZ_DATA_ERROR as _) => panic!("BZ_DATA_ERROR"), + r if r == (BZ_DATA_ERROR_MAGIC as _) => panic!("BZ_DATA_ERROR"), + r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"), + r if r == (BZ_OK as _) => panic!("BZ_OK"), + r if r == (BZ_STREAM_END as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + // Close the decompression stream. + let result = BZ2_bzDecompressEnd(&mut stream as *mut _); + match result { + r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"), + r if r == (BZ_OK as _) => {}, + r => panic!("Unknown return value = {}", r), + } + + assert_eq!(input, &decompressed_output[..]); + } + } +} +``` + +Now let's run `cargo test` again and verify that everying is linking and binding +properly! + +```bash +$ cargo test + Compiling libbindgen-tutorial-bzip2-sys v0.1.0 + Finished debug [unoptimized + debuginfo] target(s) in 0.54 secs + Running target/debug/deps/libbindgen_tutorial_bzip2_sys-1c5626bbc4401c3a + +running 15 tests +test bindgen_test_layout___darwin_pthread_handler_rec ... ok +test bindgen_test_layout___sFILE ... ok +test bindgen_test_layout___sbuf ... ok +test bindgen_test_layout__bindgen_ty_1 ... ok +test bindgen_test_layout__bindgen_ty_2 ... ok +test bindgen_test_layout__opaque_pthread_attr_t ... ok +test bindgen_test_layout__opaque_pthread_cond_t ... ok +test bindgen_test_layout__opaque_pthread_condattr_t ... ok +test bindgen_test_layout__opaque_pthread_mutex_t ... ok +test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok +test bindgen_test_layout__opaque_pthread_once_t ... ok +test bindgen_test_layout__opaque_pthread_rwlock_t ... ok +test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok +test bindgen_test_layout__opaque_pthread_t ... ok + block 1: crc = 0x47bfca17, combined CRC = 0x47bfca17, size = 2857 + bucket sorting ... + depth 1 has 2849 unresolved strings + depth 2 has 2702 unresolved strings + depth 4 has 1508 unresolved strings + depth 8 has 538 unresolved strings + depth 16 has 148 unresolved strings + depth 32 has 0 unresolved strings + reconstructing block ... + 2857 in block, 2221 after MTF & 1-2 coding, 61+2 syms in use + initial group 5, [0 .. 1], has 570 syms (25.7%) + initial group 4, [2 .. 2], has 256 syms (11.5%) + initial group 3, [3 .. 6], has 554 syms (24.9%) + initial group 2, [7 .. 12], has 372 syms (16.7%) + initial group 1, [13 .. 62], has 469 syms (21.1%) + pass 1: size is 2743, grp uses are 13 6 15 0 11 + pass 2: size is 1216, grp uses are 13 7 15 0 10 + pass 3: size is 1214, grp uses are 13 8 14 0 10 + pass 4: size is 1213, grp uses are 13 9 13 0 10 + bytes: mapping 19, selectors 17, code lengths 79, codes 1213 + final combined CRC = 0x47bfca17 + + [1: huff+mtf rt+rld {0x47bfca17, 0x47bfca17}] + combined CRCs: stored = 0x47bfca17, computed = 0x47bfca17 +test tests::round_trip_compression_decompression ... ok + +test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests libbindgen-tutorial-bzip2-sys + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` diff --git a/book/src/tutorial-6.md b/book/src/tutorial-6.md new file mode 100644 index 0000000000..366be42140 --- /dev/null +++ b/book/src/tutorial-6.md @@ -0,0 +1,13 @@ +# Publish Your Crate! + +That's it! Now we can publish our crate on crates.io and we can write a nice, +Rust-y API wrapping the raw FFI bindings in a safe interface. However, there is +already a [`bzip2-sys`][bz-sys] crate providing raw FFI bindings, and there is +already a [`bzip2`][bz] crate providing a nice, safe, Rust-y API on top of the +bindings, so we have nothing left to do here! + +Check out the [full code on Github!][example] + +[bz-sys]: https://crates.io/crates/bzip2-sys +[bz]: https://crates.io/crates/bzip2 +[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys diff --git a/book/src/whitelisting.md b/book/src/whitelisting.md new file mode 100644 index 0000000000..1b3eeaf657 --- /dev/null +++ b/book/src/whitelisting.md @@ -0,0 +1,31 @@ +# Whitelisting + +Whitelisting allows us to be precise about which type, function, and global +variable definitions `bindgen` generates bindings for. By default, if we don't +specify any whitelisting rules, everything is considered whitelisted. This may +not be desirable because of either + +* the generated bindings contain a lot of extra defintions we don't plan on using, or +* the header file contains C++ features for which Rust does not have a + corresponding form (such as partial template specialization), and we would + like to avoid these definitions + +If we specify whitelisting rules, then `bindgen` will only generate bindings to +types, functions, and global variables that match the whitelisting rules, or are +transitively used by a definition that matches them. + +### Library + +* [`bindgen::Builder::whitelisted_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_type) +* [`bindgen::Builder::whitelisted_function`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function) +* [`bindgen::Builder::whitelisted_var`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function) + +### Command Line + +* `--whitelist-type ` +* `--whitelist-function ` +* `--whitelist-var ` + +### Annotations + +None. diff --git a/ci/deploy-book.sh b/ci/deploy-book.sh new file mode 100755 index 0000000000..0c2a2b5ff9 --- /dev/null +++ b/ci/deploy-book.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -xeu +cd "$(dirname "$0")/../book" + +# Ensure mdbook is installed. +cargo install mdbook || true +export PATH="$PATH:~/.cargo/bin" + +# Get the git revision we are on. +rev=$(git rev-parse --short HEAD) + +# Build the users guide book and go into the built book's directory. +rm -rf ./book +mdbook build +cd ./book + +# Make the built book directory a new git repo, fetch upstream, make a new +# commit on gh-pages, and push it upstream. + +git init +git config user.name "Travis CI" +git config user.email "builds@travis-ci.org" + +git remote add upstream "https://$GH_TOKEN@github.com/servo/rust-bindgen.git" +git fetch upstream +git reset upstream/gh-pages + +touch . + +git add -A . +git commit -m "Rebuild users guide at ${rev}" +git push upstream HEAD:gh-pages diff --git a/ci/test-book.sh b/ci/test-book.sh new file mode 100755 index 0000000000..30b233180f --- /dev/null +++ b/ci/test-book.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -xeu +cd "$(dirname "$0")/../book" + +cargo install mdbook || true +export PATH="$PATH:~/.cargo/bin" + +mdbook build +mdbook test diff --git a/src/clang.rs b/src/clang.rs index b4acf2046f..cdadce1c1c 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -77,6 +77,30 @@ impl Cursor { } } + /// Gets the C++ manglings for this cursor, or an error if the function is + /// not loaded or the manglings are not available. + pub fn cxx_manglings(&self) -> Result, ()> { + use clang_sys::*; + if !clang_Cursor_getCXXManglings::is_loaded() { + return Err(()); + } + unsafe { + let manglings = clang_Cursor_getCXXManglings(self.x); + if manglings.is_null() { + return Err(()); + } + let count = (*manglings).Count as usize; + + let mut result = Vec::with_capacity(count); + for i in 0..count { + let string_ptr = (*manglings).Strings.offset(i as isize); + result.push(cxstring_to_string_leaky(*string_ptr)); + } + clang_disposeStringSet(manglings); + Ok(result) + } + } + /// Returns whether the cursor refers to a built-in definition. pub fn is_builtin(&self) -> bool { let (file, _, _, _) = self.location().location(); @@ -1168,16 +1192,18 @@ impl File { } } -fn cxstring_into_string(s: CXString) -> String { +fn cxstring_to_string_leaky(s: CXString) -> String { if s.data.is_null() { return "".to_owned(); } - unsafe { - let c_str = CStr::from_ptr(clang_getCString(s) as *const _); - let ret = c_str.to_string_lossy().into_owned(); - clang_disposeString(s); - ret - } + let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) }; + c_str.to_string_lossy().into_owned() +} + +fn cxstring_into_string(s: CXString) -> String { + let ret = cxstring_to_string_leaky(s); + unsafe { clang_disposeString(s) }; + ret } /// An `Index` is an environment for a set of translation units that will diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index a5df8945ee..064e9356b0 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1047,13 +1047,16 @@ impl CodeGenerator for CompInfo { // generate tuple struct if struct or union is a forward declaration, // skip for now if template parameters are needed. + // + // NB: We generate a proper struct to avoid struct/function name + // collisions. if self.is_forward_declaration() && used_template_params.is_none() { let struct_name = item.canonical_name(ctx); let struct_name = ctx.rust_ident_raw(&struct_name); let tuple_struct = quote_item!(ctx.ext_cx(), #[repr(C)] #[derive(Debug, Copy, Clone)] - pub struct $struct_name([u8; 0]); + pub struct $struct_name { _unused: [u8; 0] }; ) .unwrap(); result.push(tuple_struct); @@ -1462,11 +1465,20 @@ impl CodeGenerator for CompInfo { let mut generics = aster::AstBuilder::new().generics(); if let Some(ref params) = used_template_params { - for ty in params.iter() { + for (idx, ty) in params.iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name); + generics = generics.ty_param_id(ident); + + let prefix = ctx.trait_prefix(); + let phantom_ty = quote_ty!( + ctx.ext_cx(), + ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); + let phantom_field = StructFieldBuilder::named(format!("_phantom_{}", idx)) + .build_ty(phantom_ty); + fields.push(phantom_field); } } @@ -3322,3 +3334,4 @@ mod utils { }).collect::>() } } + diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 80c51b8f3e..91593b7934 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -500,11 +500,19 @@ impl CompInfo { let mut maybe_anonymous_struct_field = None; cursor.visit(|cur| { if cur.kind() != CXCursor_FieldDecl { - if let Some((ty, _, offset)) = + if let Some((ty, clang_ty, offset)) = maybe_anonymous_struct_field.take() { - let field = - Field::new(None, ty, None, None, None, false, offset); - ci.fields.push(field); + if cur.kind() == CXCursor_TypedefDecl && + cur.typedef_type().unwrap().canonical_type() == clang_ty { + // Typedefs of anonymous structs appear later in the ast + // than the struct itself, that would otherwise be an + // anonymous field. Detect that case here, and do + // nothing. + } else { + let field = + Field::new(None, ty, None, None, None, false, offset); + ci.fields.push(field); + } } } @@ -580,21 +588,19 @@ impl CompInfo { CXCursor_ClassTemplate | CXCursor_ClassDecl => { // We can find non-semantic children here, clang uses a - // StructDecl to note incomplete structs that hasn't been - // forward-declared before, see: + // StructDecl to note incomplete structs that haven't been + // forward-declared before, see [1]. // // Also, clang seems to scope struct definitions inside - // unions to the whole translation unit. Since those are - // anonymous, let's just assume that if the cursor we've - // found is a definition it's a valid inner type. + // unions, and other named struct definitions inside other + // structs to the whole translation unit. // - // Note that doing this could be always ok, but let's just - // keep the union check for now. + // Let's just assume that if the cursor we've found is a + // definition, it's a valid inner type. // - // https://github.com/servo/rust-bindgen/issues/482 + // [1]: https://github.com/servo/rust-bindgen/issues/482 let is_inner_struct = cur.semantic_parent() == cursor || - (kind == CompKind::Union && - cur.is_definition()); + cur.is_definition(); if !is_inner_struct { return CXChildVisit_Continue; } @@ -737,7 +743,8 @@ impl CompInfo { }); if let Some((ty, _, offset)) = maybe_anonymous_struct_field { - let field = Field::new(None, ty, None, None, None, false, offset); + let field = + Field::new(None, ty, None, None, None, false, offset); ci.fields.push(field); } @@ -968,6 +975,17 @@ impl Trace for CompInfo { tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition); } + for &ty in self.inner_types() { + tracer.visit_kind(ty, EdgeKind::InnerType); + } + + // We unconditionally trace `CompInfo`'s template parameters and inner + // types for the the usage analysis. However, we don't want to continue + // tracing anything else, if this type is marked opaque. + if item.is_opaque(context) { + return; + } + for base in self.base_members() { tracer.visit_kind(base.ty, EdgeKind::BaseMember); } @@ -976,10 +994,6 @@ impl Trace for CompInfo { tracer.visit_kind(field.ty(), EdgeKind::Field); } - for &ty in self.inner_types() { - tracer.visit_kind(ty, EdgeKind::InnerType); - } - for &var in self.inner_vars() { tracer.visit_kind(var, EdgeKind::InnerVar); } diff --git a/src/ir/context.rs b/src/ir/context.rs index 60ea90c6bc..3d3e9fcdb4 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -163,12 +163,53 @@ pub struct BindgenContext<'ctx> { } /// A traversal of whitelisted items. -pub type WhitelistedItems<'ctx, 'gen> = ItemTraversal<'ctx, - 'gen, - ItemSet, - Vec, - fn(Edge) -> bool>; +pub struct WhitelistedItems<'ctx, 'gen> + where 'gen: 'ctx +{ + ctx: &'ctx BindgenContext<'gen>, + traversal: ItemTraversal<'ctx, + 'gen, + ItemSet, + Vec, + fn(Edge) -> bool>, +} + +impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen> + where 'gen: 'ctx +{ + type Item = ItemId; + + fn next(&mut self) -> Option { + loop { + match self.traversal.next() { + None => return None, + Some(id) if self.ctx.resolve_item(id).is_hidden(self.ctx) => continue, + Some(id) => return Some(id), + } + } + } +} +impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen> + where 'gen: 'ctx +{ + /// Construct a new whitelisted items traversal. + pub fn new(ctx: &'ctx BindgenContext<'gen>, + roots: R) + -> WhitelistedItems<'ctx, 'gen> + where R: IntoIterator, + { + let predicate = if ctx.options().whitelist_recursively { + traversal::all_edges + } else { + traversal::no_edges + }; + WhitelistedItems { + ctx: ctx, + traversal: ItemTraversal::new(ctx, roots, predicate) + } + } +} impl<'ctx> BindgenContext<'ctx> { /// Construct the context for the given `options`. pub fn new(options: BindgenOptions) -> Self { @@ -646,12 +687,21 @@ impl<'ctx> BindgenContext<'ctx> { assert!(self.in_codegen_phase(), "We only compute template parameter usage as we enter codegen"); + if self.resolve_item(item).is_hidden(self) { + return true; + } + + let template_param = template_param.into_resolver() + .through_type_refs() + .through_type_aliases() + .resolve(self) + .id(); + self.used_template_parameters .as_ref() .expect("should have found template parameter usage if we're in codegen") .get(&item) - .map(|items_used_params| items_used_params.contains(&template_param)) - .unwrap_or_else(|| self.resolve_item(item).is_hidden(self)) + .map_or(false, |items_used_params| items_used_params.contains(&template_param)) } // This deserves a comment. Builtin types don't get a valid declaration, so @@ -1214,7 +1264,7 @@ impl<'ctx> BindgenContext<'ctx> { } /// Tokenizes a namespace cursor in order to get the name and kind of the - /// namespace, + /// namespace. fn tokenize_namespace(&self, cursor: &clang::Cursor) -> (Option, ModuleKind) { @@ -1230,6 +1280,7 @@ impl<'ctx> BindgenContext<'ctx> { let mut kind = ModuleKind::Normal; let mut found_namespace_keyword = false; let mut module_name = None; + while let Some(token) = iter.next() { match &*token.spelling { "inline" => { @@ -1237,7 +1288,17 @@ impl<'ctx> BindgenContext<'ctx> { assert!(kind != ModuleKind::Inline); kind = ModuleKind::Inline; } - "namespace" => { + // The double colon allows us to handle nested namespaces like + // namespace foo::bar { } + // + // libclang still gives us two namespace cursors, which is cool, + // but the tokenization of the second begins with the double + // colon. That's ok, so we only need to handle the weird + // tokenization here. + // + // Fortunately enough, inline nested namespace specifiers aren't + // a thing, and are invalid C++ :) + "namespace" | "::" => { found_namespace_keyword = true; } "{" => { @@ -1374,14 +1435,7 @@ impl<'ctx> BindgenContext<'ctx> { // unions). let mut roots: Vec<_> = roots.collect(); roots.reverse(); - - let predicate = if self.options().whitelist_recursively { - traversal::all_edges - } else { - traversal::no_edges - }; - - WhitelistedItems::new(self, roots, predicate) + WhitelistedItems::new(self, roots) } /// Convenient method for getting the prefix to use for most traits in diff --git a/src/ir/function.rs b/src/ir/function.rs index 0809b3c28e..23503b05cc 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -126,6 +126,12 @@ pub fn cursor_mangling(ctx: &BindgenContext, return None; } + if let Ok(mut manglings) = cursor.cxx_manglings() { + if let Some(m) = manglings.pop() { + return Some(m); + } + } + let mut mangling = cursor.mangling(); if mangling.is_empty() { return None; diff --git a/src/ir/item.rs b/src/ir/item.rs index 20451bbc1b..a60697b889 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -217,9 +217,12 @@ impl Trace for Item { fn trace(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &()) where T: Tracer, { - if self.is_hidden(ctx) { - return; - } + // Even if this item is blacklisted/hidden, we want to trace it. It is + // traversal iterators' consumers' responsibility to filter items as + // needed. Generally, this filtering happens in the implementation of + // `Iterator` for `WhitelistedItems`. Fully tracing blacklisted items is + // necessary for things like the template parameter usage analysis to + // function correctly. match *self.kind() { ItemKind::Type(ref ty) => { diff --git a/src/ir/named.rs b/src/ir/named.rs index 84a633795b..943d3a5748 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -128,7 +128,7 @@ use super::context::{BindgenContext, ItemId}; use super::item::{Item, ItemSet}; -use super::template::{AsNamed, TemplateInstantiation, TemplateParameters}; +use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{EdgeKind, Trace}; use super::ty::TypeKind; use std::collections::{HashMap, HashSet}; @@ -222,12 +222,18 @@ pub fn analyze(extra: Analysis::Extra) -> Analysis::Output /// ``` /// /// * If `inst` is a template instantiation, `inst.args` are the template -/// instantiation's template arguments, and `inst.def` is the template -/// definition being instantiated: +/// instantiation's template arguments, `inst.def` is the template definition +/// being instantiated, and `inst.def.params` is the template definition's +/// template parameters, then the instantiation's usage is the union of each +/// of its arguments' usages *if* the corresponding template parameter is in +/// turn used by the template definition: /// /// ```ignore -/// template_param_usage(inst) = -/// { T: for T in inst.args, if T in template_param_usage(inst.def) } +/// template_param_usage(inst) = union( +/// template_param_usage(inst.args[i]) +/// for i in 0..length(inst.args.length) +/// if inst.def.params[i] in template_param_usage(inst.def) +/// ) /// ``` /// /// * Finally, for all other IR item kinds, we use our lattice's `join` @@ -243,6 +249,15 @@ pub fn analyze(extra: Analysis::Extra) -> Analysis::Output /// template declaration to its template parameters' definitions for this /// analysis. If we didn't, then we would mistakenly determine that ever /// template parameter is always used. +/// +/// The final wrinkle is handling of blacklisted types. Normally, we say that +/// the set of whitelisted items is the transitive closure of items explicitly +/// called out for whitelisting, *without* any items explicitly called out as +/// blacklisted. However, for the purposes of this analysis's correctness, we +/// simplify and consider run the analysis on the full transitive closure of +/// whitelisted items. We do, however, treat instantiations of blacklisted items +/// specially; see `constrain_instantiation_of_blacklisted_template` and its +/// documentation for details. #[derive(Debug, Clone)] pub struct UsedTemplateParameters<'ctx, 'gen> where 'gen: 'ctx, @@ -255,6 +270,9 @@ pub struct UsedTemplateParameters<'ctx, 'gen> dependencies: HashMap>, + // The set of whitelisted items, without any blacklisted items reachable + // from the whitelisted items which would otherwise be considered + // whitelisted as well. whitelisted_items: HashSet, } @@ -315,20 +333,40 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { /// what they'll to with template parameters, but we can push the issue down /// the line to them. fn constrain_instantiation_of_blacklisted_template(&self, + this_id: ItemId, used_by_this_id: &mut ItemSet, instantiation: &TemplateInstantiation) { trace!(" instantiation of blacklisted template, uses all template \ arguments"); let args = instantiation.template_arguments() - .iter() - .filter_map(|a| a.as_named(self.ctx, &())); + .into_iter() + .map(|a| { + a.into_resolver() + .through_type_refs() + .through_type_aliases() + .resolve(self.ctx) + .id() + }) + .filter(|a| *a != this_id) + .flat_map(|a| { + self.used.get(&a) + .expect("Should have a used entry for the template arg") + .as_ref() + .expect("Because a != this_id, and all used template \ + param sets other than this_id's are `Some`, \ + a's used template param set should be `Some`") + .iter() + .cloned() + }); + used_by_this_id.extend(args); } /// A template instantiation's concrete template argument is only used if /// the template definition uses the corresponding template parameter. fn constrain_instantiation(&self, + this_id: ItemId, used_by_this_id: &mut ItemSet, instantiation: &TemplateInstantiation) { trace!(" template instantiation"); @@ -339,9 +377,14 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { let params = decl.self_template_params(self.ctx) .unwrap_or(vec![]); - let used_by_def = self.used[&instantiation.template_definition()] + debug_assert!(this_id != instantiation.template_definition()); + let used_by_def = self.used + .get(&instantiation.template_definition()) + .expect("Should have a used entry for instantiation's template definition") .as_ref() - .unwrap(); + .expect("And it should be Some because only this_id's set is None, and an \ + instantiation's template definition should never be the \ + instantiation itself"); for (arg, param) in args.iter().zip(params.iter()) { trace!(" instantiation's argument {:?} is used if definition's \ @@ -355,11 +398,24 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { let arg = arg.into_resolver() .through_type_refs() .through_type_aliases() - .resolve(self.ctx); - if let Some(named) = arg.as_named(self.ctx, &()) { - trace!(" arg is a type parameter, marking used"); - used_by_this_id.insert(named); + .resolve(self.ctx) + .id(); + + if arg == this_id { + continue; } + + let used_by_arg = self.used + .get(&arg) + .expect("Should have a used entry for the template arg") + .as_ref() + .expect("Because arg != this_id, and all used template \ + param sets other than this_id's are `Some`, \ + arg's used template param set should be \ + `Some`") + .iter() + .cloned(); + used_by_this_id.extend(used_by_arg); } } } @@ -372,14 +428,14 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { item.trace(self.ctx, &mut |sub_id, edge_kind| { // Ignore ourselves, since union with ourself is a // no-op. Ignore edges that aren't relevant to the - // analysis. Ignore edges to blacklisted items. - if sub_id == item.id() || - !Self::consider_edge(edge_kind) || - !self.whitelisted_items.contains(&sub_id) { - return; - } + // analysis. + if sub_id == item.id() || !Self::consider_edge(edge_kind) { + return; + } - let used_by_sub_id = self.used[&sub_id] + let used_by_sub_id = self.used + .get(&sub_id) + .expect("Should have a used set for the sub_id successor") .as_ref() .expect("Because sub_id != id, and all used template \ param sets other than id's are `Some`, \ @@ -408,26 +464,26 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { let mut dependencies = HashMap::new(); let whitelisted_items: HashSet<_> = ctx.whitelisted_items().collect(); - for item in whitelisted_items.iter().cloned() { + let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items.iter() + .cloned() + .flat_map(|i| { + let mut reachable = vec![i]; + i.trace(ctx, &mut |s, _| { + reachable.push(s); + }, &()); + reachable + }) + .collect(); + + for item in whitelisted_and_blacklisted_items { dependencies.entry(item).or_insert(vec![]); used.entry(item).or_insert(Some(ItemSet::new())); { // We reverse our natural IR graph edges to find dependencies // between nodes. - item.trace(ctx, &mut |sub_item, _| { + item.trace(ctx, &mut |sub_item: ItemId, _| { used.entry(sub_item).or_insert(Some(ItemSet::new())); - - // We won't be generating code for items that aren't - // whitelisted, so don't bother keeping track of their - // template parameters. But isn't whitelisting the - // transitive closure of reachable items from the explicitly - // whitelisted items? Usually! The exception is explicitly - // blacklisted items. - if !whitelisted_items.contains(&sub_item) { - return; - } - dependencies.entry(sub_item) .or_insert(vec![]) .push(item); @@ -451,12 +507,24 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { .unwrap_or(vec![]); for (arg, param) in args.iter().zip(params.iter()) { - used.entry(*arg).or_insert(Some(ItemSet::new())); - used.entry(*param).or_insert(Some(ItemSet::new())); - - dependencies.entry(*arg) + let arg = arg.into_resolver() + .through_type_aliases() + .through_type_refs() + .resolve(ctx) + .id(); + + let param = param.into_resolver() + .through_type_aliases() + .through_type_refs() + .resolve(ctx) + .id(); + + used.entry(arg).or_insert(Some(ItemSet::new())); + used.entry(param).or_insert(Some(ItemSet::new())); + + dependencies.entry(arg) .or_insert(vec![]) - .push(*param); + .push(param); } } _ => {} @@ -468,21 +536,20 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // item, as well as all explicitly blacklisted items that are // reachable from whitelisted items. // + // Invariant: the `dependencies` map has an entry for every + // whitelisted item. + // // (This is so that every item we call `constrain` on is guaranteed // to have a set of template parameters, and we can allow // blacklisted templates to use all of their parameters). for item in whitelisted_items.iter() { extra_assert!(used.contains_key(item)); + extra_assert!(dependencies.contains_key(item)); item.trace(ctx, &mut |sub_item, _| { extra_assert!(used.contains_key(&sub_item)); + extra_assert!(dependencies.contains_key(&sub_item)); }, &()) } - - // Invariant: the `dependencies` map has an entry for every - // whitelisted item. - for item in whitelisted_items.iter() { - extra_assert!(dependencies.contains_key(item)); - } } UsedTemplateParameters { @@ -494,7 +561,18 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { } fn initial_worklist(&self) -> Vec { - self.ctx.whitelisted_items().collect() + // The transitive closure of all whitelisted items, including explicitly + // blacklisted items. + self.ctx + .whitelisted_items() + .flat_map(|i| { + let mut reachable = vec![i]; + i.trace(self.ctx, &mut |s, _| { + reachable.push(s); + }, &()); + reachable + }) + .collect() } fn constrain(&mut self, id: ItemId) -> bool { @@ -525,9 +603,10 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // template definition uses the corresponding template parameter. Some(&TypeKind::TemplateInstantiation(ref inst)) => { if self.whitelisted_items.contains(&inst.template_definition()) { - self.constrain_instantiation(&mut used_by_this_id, inst); + self.constrain_instantiation(id, &mut used_by_this_id, inst); } else { - self.constrain_instantiation_of_blacklisted_template(&mut used_by_this_id, + self.constrain_instantiation_of_blacklisted_template(id, + &mut used_by_this_id, inst); } } diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index 95d2a45675..0072e6b282 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -25,16 +25,6 @@ impl Edge { kind: kind, } } - - /// Get the item that this edge is pointing to. - pub fn to(&self) -> ItemId { - self.to - } - - /// Get the kind of edge that this is. - pub fn kind(&self) -> EdgeKind { - self.kind - } } impl Into for Edge { diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 9fabf98087..c3f26572fb 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -345,6 +345,7 @@ impl Type { /// item, so we can arrive to the proper item that needs to be generated. pub fn should_be_traced_unconditionally(&self) -> bool { match self.kind { + TypeKind::Comp(..) | TypeKind::Function(..) | TypeKind::Pointer(..) | TypeKind::Array(..) | diff --git a/src/lib.rs b/src/lib.rs index 1e762f72ed..5d8237fbff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ //! functions and use types defined in the header. //! -//! See the [Builder](./struct.Builder.html) struct for usage. +//! See the [`Builder`](./struct.Builder.html) struct for usage. #![deny(missing_docs)] #![deny(warnings)] @@ -175,7 +175,7 @@ pub fn builder() -> Builder { } impl Builder { - ///Generates the command line flags use for creating `builder` + /// Generates the command line flags use for creating `Builder`. pub fn command_line_flags(&self) -> Vec { let mut output_vector: Vec = Vec::new(); @@ -416,8 +416,34 @@ impl Builder { output_vector } - /// Set the input C/C++ header. + /// Add an input C/C++ header to generate bindings for. + /// + /// This can be used to generate bindings to a single header: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("input.h") + /// .generate() + /// .unwrap(); + /// ``` + /// + /// Or you can invoke it multiple times to generate bindings to multiple + /// headers: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("first.h") + /// .header("second.h") + /// .header("third.h") + /// .generate() + /// .unwrap(); + /// ``` pub fn header>(mut self, header: T) -> Builder { + if let Some(prev_header) = self.options.input_header.take() { + self.options.clang_args.push("-include".into()); + self.options.clang_args.push(prev_header); + } + let header = header.into(); self.options.input_header = Some(header); self @@ -455,21 +481,21 @@ impl Builder { /// /// This can be used to get bindgen to generate _exactly_ the types you want /// in your bindings, and then import other types manually via other means - /// (like `raw_line`). + /// (like [`raw_line`](#method.raw_line)). pub fn whitelist_recursively(mut self, doit: bool) -> Self { self.options.whitelist_recursively = doit; self } - /// Generate '#[macro_use] extern crate objc;' instead of 'use objc;' + /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` /// in the prologue of the files generated from objective-c files pub fn objc_extern_crate(mut self, doit: bool) -> Self { self.options.objc_extern_crate = doit; self } - /// Whether to use the clang-provided name mangling. This is true and - /// probably needed for C++ features. + /// Whether to use the clang-provided name mangling. This is true by default + /// and probably needed for C++ features. /// /// However, some old libclang versions seem to return incorrect results in /// some cases for non-mangled functions, see [1], so we allow disabling it. @@ -593,7 +619,7 @@ impl Builder { self } - /// Avoid converting floats to f32/f64 by default. + /// Avoid converting floats to `f32`/`f64` by default. pub fn no_convert_floats(mut self) -> Self { self.options.convert_floats = false; self @@ -635,20 +661,19 @@ impl Builder { self } - /// Disable auto-namespacing of names if namespaces are disabled. + /// Disable name auto-namespacing. /// - /// By default, if namespaces are disabled, bindgen tries to mangle the - /// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of - /// just `Baz`. + /// By default, bindgen mangles names like `foo::bar::Baz` to look like + /// `foo_bar_Baz` instead of just `Baz`. /// - /// This option disables that behavior. + /// This method disables that behavior. /// - /// Note that this intentionally doesn't change the names using for - /// whitelisting and blacklisting, that should still be mangled with the + /// Note that this intentionally does not change the names used for + /// whitelisting and blacklisting, which should still be mangled with the /// namespaces. /// - /// Note, also, that using this option may cause duplicated names to be - /// generated. + /// Note, also, that this option may cause bindgen to generate duplicate + /// names. pub fn disable_name_namespacing(mut self) -> Builder { self.options.disable_name_namespacing = true; self @@ -727,14 +752,15 @@ impl Builder { self } - /// Allows configuring types in different situations, see the `ParseCallbacks` - /// documentation. + /// Allows configuring types in different situations, see the + /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. pub fn parse_callbacks(mut self, cb: Box) -> Self { self.options.parse_callbacks = Some(cb); self } - /// Choose what to generate using a CodegenConfig. + /// Choose what to generate using a + /// [`CodegenConfig`](./struct.CodegenConfig.html). pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { self.options.codegen_config = config; self diff --git a/src/main.rs b/src/main.rs index 2ba2b1394a..603a655562 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ extern crate env_logger; extern crate log; extern crate clang_sys; extern crate clap; -extern crate rustc_serialize; use bindgen::clang_version; use std::env; diff --git a/src/options.rs b/src/options.rs index 9072abd820..ca54dbc643 100644 --- a/src/options.rs +++ b/src/options.rs @@ -35,7 +35,7 @@ pub fn builder_from_flags .number_of_values(1), Arg::with_name("blacklist-type") .long("blacklist-type") - .help("Mark a type as hidden.") + .help("Mark as hidden.") .value_name("type") .takes_value(true) .multiple(true) @@ -52,17 +52,17 @@ pub fn builder_from_flags .help("Avoid deriving Default on any type."), Arg::with_name("with-derive-default") .long("with-derive-default") - .help("Deriving Default on any type."), + .help("Derive Default on any type."), Arg::with_name("no-doc-comments") .long("no-doc-comments") .help("Avoid including doc comments in the output, see: \ https://github.com/servo/rust-bindgen/issues/426"), Arg::with_name("no-recursive-whitelist") .long("no-recursive-whitelist") - .help("Avoid whitelisting types recursively"), + .help("Avoid whitelisting types recursively."), Arg::with_name("objc-extern-crate") .long("objc-extern-crate") - .help("Use extern crate instead of use for objc"), + .help("Use extern crate instead of use for objc."), Arg::with_name("distrust-clang-mangling") .long("distrust-clang-mangling") .help("Do not trust the libclang-provided mangling"), @@ -100,7 +100,9 @@ pub fn builder_from_flags .help("Enable support for C++ namespaces."), Arg::with_name("disable-name-namespacing") .long("disable-name-namespacing") - .help("Disable name namespacing if namespaces are disabled."), + .help("Disable namespacing via mangling, causing bindgen to \ + generate names like \"Baz\" instead of \"foo_bar_Baz\" \ + for an input name \"foo::bar::Baz\"."), Arg::with_name("framework") .long("framework-link") .help("Link to framework.") @@ -113,7 +115,7 @@ pub fn builder_from_flags is useful when you only care about struct layouts."), Arg::with_name("generate") .long("generate") - .help("Generate a given kind of items, split by commas. \ + .help("Generate only given items, split by commas. \ Valid values are \"functions\",\"types\", \"vars\", \ \"methods\", \"constructors\" and \"destructors\".") .takes_value(true), @@ -129,17 +131,17 @@ pub fn builder_from_flags .number_of_values(1), Arg::with_name("no-convert-floats") .long("no-convert-floats") - .help("Don't automatically convert floats to f32/f64."), + .help("Do not automatically convert floats to f32/f64."), Arg::with_name("no-prepend-enum-name") .long("no-prepend-enum-name") - .help("Do not prepend the enum name to bitfield or constant variants"), + .help("Do not prepend the enum name to bitfield or constant variants."), Arg::with_name("no-unstable-rust") .long("no-unstable-rust") .help("Do not generate unstable Rust code.") .multiple(true), // FIXME: Pass legacy test suite Arg::with_name("opaque-type") .long("opaque-type") - .help("Mark a type as opaque.") + .help("Mark as opaque.") .value_name("type") .takes_value(true) .multiple(true) @@ -182,7 +184,7 @@ pub fn builder_from_flags .number_of_values(1), Arg::with_name("generate-inline-functions") .long("generate-inline-functions") - .help("Whether inline functions should be generated."), + .help("Generate inline functions."), Arg::with_name("whitelist-type") .long("whitelist-type") .help("Whitelist the type. Other non-whitelisted types will \ @@ -202,7 +204,7 @@ pub fn builder_from_flags .number_of_values(1), Arg::with_name("verbose") .long("verbose") - .help("Print verbose error messages"), + .help("Print verbose error messages."), ]) // .args() .get_matches_from(args); diff --git a/tests/expectations/tests/anonymous-template-types.rs b/tests/expectations/tests/anonymous-template-types.rs index c225b69d27..50604a3f1b 100644 --- a/tests/expectations/tests/anonymous-template-types.rs +++ b/tests/expectations/tests/anonymous-template-types.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Foo { pub t_member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -21,6 +22,7 @@ pub struct Bar { #[derive(Debug, Copy, Clone)] pub struct Quux { pub v_member: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Quux { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index b92976f6a0..8446cbcdf6 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -53,6 +53,7 @@ impl Clone for A_C { #[derive(Debug, Copy, Clone)] pub struct A_D { pub foo: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for A_D { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -115,11 +116,13 @@ impl Clone for D { #[derive(Debug, Copy, Clone)] pub struct Templated { pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Templated_Templated_inner { pub member_ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Templated_Templated_inner { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 495889f256..3b15b89138 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -8,6 +8,7 @@ #[derive(Debug)] pub struct HandleWithDtor { pub ptr: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for HandleWithDtor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/const_tparam.rs b/tests/expectations/tests/const_tparam.rs index f47ca08244..7600e18eed 100644 --- a/tests/expectations/tests/const_tparam.rs +++ b/tests/expectations/tests/const_tparam.rs @@ -9,6 +9,7 @@ pub struct C { pub foo: *const T, pub bar: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for C { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/default-template-parameter.rs b/tests/expectations/tests/default-template-parameter.rs index af4616ff9b..c098dac7b5 100644 --- a/tests/expectations/tests/default-template-parameter.rs +++ b/tests/expectations/tests/default-template-parameter.rs @@ -9,6 +9,8 @@ pub struct Foo { pub t: T, pub u: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/forward-declaration-autoptr.rs b/tests/expectations/tests/forward-declaration-autoptr.rs index b05984c8c8..e129e0fb4d 100644 --- a/tests/expectations/tests/forward-declaration-autoptr.rs +++ b/tests/expectations/tests/forward-declaration-autoptr.rs @@ -6,11 +6,14 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Foo([u8; 0]); +pub struct Foo { + _unused: [u8; 0], +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct RefPtr { pub m_inner: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for RefPtr { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/forward-inherit-struct-with-fields.rs b/tests/expectations/tests/forward-inherit-struct-with-fields.rs index ce61a5459c..1b31f62b57 100644 --- a/tests/expectations/tests/forward-inherit-struct-with-fields.rs +++ b/tests/expectations/tests/forward-inherit-struct-with-fields.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Rooted { pub _base: js_RootedBase, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for Rooted { pub struct js_RootedBase { pub foo: *mut T, pub next: *mut Rooted, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for js_RootedBase { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/forward_declared_complex_types.rs b/tests/expectations/tests/forward_declared_complex_types.rs index a6e67f7b77..03330b2fbe 100644 --- a/tests/expectations/tests/forward_declared_complex_types.rs +++ b/tests/expectations/tests/forward_declared_complex_types.rs @@ -21,7 +21,9 @@ impl Clone for Foo_empty { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Foo([u8; 0]); +pub struct Foo { + _unused: [u8; 0], +} #[repr(C)] #[derive(Debug, Copy)] pub struct Bar { @@ -51,14 +53,18 @@ extern "C" { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Union([u8; 0]); +pub struct Union { + _unused: [u8; 0], +} extern "C" { #[link_name = "_Z9baz_unionP5Union"] pub fn baz_union(u: *mut Union); } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Quux([u8; 0]); +pub struct Quux { + _unused: [u8; 0], +} extern "C" { #[link_name = "_Z9baz_classP4Quux"] pub fn baz_class(q: *mut Quux); diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index 703df9ea54..a641de70b5 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -13,6 +13,7 @@ pub struct Wohoo { #[derive(Debug, Copy, Clone)] pub struct Weeee { pub _base: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Weeee { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs index 91b8e49a16..ddcaf3fc0b 100644 --- a/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs +++ b/tests/expectations/tests/issue-584-stylo-template-analysis-panic.rs @@ -43,6 +43,7 @@ impl Clone for A { #[derive(Debug, Copy, Clone)] pub struct e { pub d: RefPtr, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for e { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs index 4ff0b5bc21..3afaf62d96 100644 --- a/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs +++ b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct RefPtr { pub use_of_t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for RefPtr { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -16,6 +17,7 @@ impl Default for RefPtr { #[derive(Debug, Copy, Clone)] pub struct UsesRefPtrWithAliasedTypeParam { pub member: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type UsesRefPtrWithAliasedTypeParam_V = U; impl Default for UsesRefPtrWithAliasedTypeParam { diff --git a/tests/expectations/tests/issue-639-typedef-anon-field.rs b/tests/expectations/tests/issue-639-typedef-anon-field.rs new file mode 100644 index 0000000000..8d5709f447 --- /dev/null +++ b/tests/expectations/tests/issue-639-typedef-anon-field.rs @@ -0,0 +1,81 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Foo { + pub bar: Foo_Bar, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Foo_Bar { + pub abc: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_Foo_Bar() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( Foo_Bar ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( Foo_Bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Foo_Bar ) ) . abc as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Foo_Bar ) , "::" , + stringify ! ( abc ) )); +} +impl Clone for Foo_Bar { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( Foo ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( Foo ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Foo ) ) . bar as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Foo ) , "::" , + stringify ! ( bar ) )); +} +impl Clone for Foo { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Baz { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Baz_Bar { + pub abc: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_Baz_Bar() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( Baz_Bar ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( Baz_Bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const Baz_Bar ) ) . abc as * const _ as usize } + , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( Baz_Bar ) , "::" , + stringify ! ( abc ) )); +} +impl Clone for Baz_Bar { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Baz() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( Baz ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Baz ) )); +} +impl Clone for Baz { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/tests/issue-643-inner-struct.rs b/tests/expectations/tests/issue-643-inner-struct.rs new file mode 100644 index 0000000000..5069905b3d --- /dev/null +++ b/tests/expectations/tests/issue-643-inner-struct.rs @@ -0,0 +1,108 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData); +impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData) + } + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { ::std::mem::transmute(self) } + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} +impl ::std::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { Self::new() } +} +impl ::std::marker::Copy for __IncompleteArrayField { } +#[repr(C)] +#[derive(Debug, Copy)] +pub struct rte_ring { + pub memzone: *mut rte_memzone, + pub prod: rte_ring_prod, + pub cons: rte_ring_cons, + pub ring: __IncompleteArrayField<*mut ::std::os::raw::c_void>, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct rte_ring_prod { + pub watermark: ::std::os::raw::c_uint, +} +#[test] +fn bindgen_test_layout_rte_ring_prod() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( rte_ring_prod ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( rte_ring_prod ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const rte_ring_prod ) ) . watermark as * const + _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( rte_ring_prod ) , "::" + , stringify ! ( watermark ) )); +} +impl Clone for rte_ring_prod { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct rte_ring_cons { + pub sc_dequeue: ::std::os::raw::c_uint, +} +#[test] +fn bindgen_test_layout_rte_ring_cons() { + assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( + "Size of: " , stringify ! ( rte_ring_cons ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( rte_ring_cons ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const rte_ring_cons ) ) . sc_dequeue as * const + _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( rte_ring_cons ) , "::" + , stringify ! ( sc_dequeue ) )); +} +impl Clone for rte_ring_cons { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_rte_ring() { + assert_eq!(::std::mem::size_of::() , 16usize , concat ! ( + "Size of: " , stringify ! ( rte_ring ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( rte_ring ) )); +} +impl Clone for rte_ring { + fn clone(&self) -> Self { *self } +} +impl Default for rte_ring { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct rte_memzone { + pub _address: u8, +} +impl Clone for rte_memzone { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs b/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs new file mode 100644 index 0000000000..c9695b6958 --- /dev/null +++ b/tests/expectations/tests/issue-645-cannot-find-type-T-in-this-scope.rs @@ -0,0 +1,17 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +#[derive(Clone, Copy, Debug)] pub struct RefPtr(T); + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct HasRefPtr { + pub refptr_member: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +pub type HasRefPtr_TypedefOfT = T; +impl Default for HasRefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-654-struct-fn-collision.rs b/tests/expectations/tests/issue-654-struct-fn-collision.rs new file mode 100644 index 0000000000..c2915b3fc7 --- /dev/null +++ b/tests/expectations/tests/issue-654-struct-fn-collision.rs @@ -0,0 +1,14 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct foo { + _unused: [u8; 0], +} +extern "C" { + pub fn foo() -> ::std::os::raw::c_int; +} diff --git a/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs b/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs new file mode 100644 index 0000000000..4a81f24edb --- /dev/null +++ b/tests/expectations/tests/issue-662-cannot-find-T-in-this-scope.rs @@ -0,0 +1,33 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr { + pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for RefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsMainThreadPtrHolder { + pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsMainThreadPtrHolder { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsMainThreadPtrHandle { + pub mPtr: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsMainThreadPtrHandle { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-662-part-2.rs b/tests/expectations/tests/issue-662-part-2.rs new file mode 100644 index 0000000000..eb9a34d13d --- /dev/null +++ b/tests/expectations/tests/issue-662-part-2.rs @@ -0,0 +1,25 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +#[derive(Clone, Copy, Debug)] pub struct RefPtr(T); + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsMainThreadPtrHolder { + pub a: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsMainThreadPtrHolder { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsMainThreadPtrHandle { + pub mPtr: RefPtr>, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, +} +impl Default for nsMainThreadPtrHandle { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-674-1.rs b/tests/expectations/tests/issue-674-1.rs new file mode 100644 index 0000000000..8be8721c68 --- /dev/null +++ b/tests/expectations/tests/issue-674-1.rs @@ -0,0 +1,46 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod mozilla { + #[allow(unused_imports)] + use self::super::super::root; + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct Maybe { + pub _address: u8, + } + pub type Maybe_ValueType = T; + impl Default for Maybe { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct CapturingContentInfo { + pub a: u8, + } + #[test] + fn bindgen_test_layout_CapturingContentInfo() { + assert_eq!(::std::mem::size_of::() , 1usize , + concat ! ( + "Size of: " , stringify ! ( CapturingContentInfo ) )); + assert_eq! (::std::mem::align_of::() , 1usize , + concat ! ( + "Alignment of " , stringify ! ( CapturingContentInfo ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const CapturingContentInfo ) ) . a as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( + CapturingContentInfo ) , "::" , stringify ! ( a ) )); + } + impl Clone for CapturingContentInfo { + fn clone(&self) -> Self { *self } + } +} diff --git a/tests/expectations/tests/issue-674-2.rs b/tests/expectations/tests/issue-674-2.rs new file mode 100644 index 0000000000..1f597c9e26 --- /dev/null +++ b/tests/expectations/tests/issue-674-2.rs @@ -0,0 +1,69 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod JS { + #[allow(unused_imports)] + use self::super::super::root; + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct Rooted { + pub _address: u8, + } + pub type Rooted_ElementType = T; + impl Default for Rooted { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct c { + pub b: u8, + } + #[test] + fn bindgen_test_layout_c() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( c ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( c ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const c ) ) . b as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( c ) , "::" , + stringify ! ( b ) )); + } + impl Clone for c { + fn clone(&self) -> Self { *self } + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct B { + pub a: root::c, + } + #[test] + fn bindgen_test_layout_B() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( B ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( B ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const B ) ) . a as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( B ) , "::" , + stringify ! ( a ) )); + } + impl Clone for B { + fn clone(&self) -> Self { *self } + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct StaticRefPtr { + pub _address: u8, + } +} diff --git a/tests/expectations/tests/issue-674-3.rs b/tests/expectations/tests/issue-674-3.rs new file mode 100644 index 0000000000..69587deb7c --- /dev/null +++ b/tests/expectations/tests/issue-674-3.rs @@ -0,0 +1,60 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct nsRefPtrHashtable { + pub _address: u8, + } + pub type nsRefPtrHashtable_UserDataType = *mut PtrType; + impl Default for nsRefPtrHashtable { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct a { + pub b: u8, + } + #[test] + fn bindgen_test_layout_a() { + assert_eq!(::std::mem::size_of::
() , 1usize , concat ! ( + "Size of: " , stringify ! ( a ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( a ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const a ) ) . b as * const _ as usize } , + 0usize , concat ! ( + "Alignment of field: " , stringify ! ( a ) , "::" , + stringify ! ( b ) )); + } + impl Clone for a { + fn clone(&self) -> Self { *self } + } + #[repr(C)] + #[derive(Debug, Default, Copy)] + pub struct nsCSSValue { + pub c: root::a, + } + #[test] + fn bindgen_test_layout_nsCSSValue() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( nsCSSValue ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( nsCSSValue ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const nsCSSValue ) ) . c as * const _ as + usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( nsCSSValue ) , "::" + , stringify ! ( c ) )); + } + impl Clone for nsCSSValue { + fn clone(&self) -> Self { *self } + } +} diff --git a/tests/expectations/tests/issue-677-nested-ns-specifier.rs b/tests/expectations/tests/issue-677-nested-ns-specifier.rs new file mode 100644 index 0000000000..44d9904ac8 --- /dev/null +++ b/tests/expectations/tests/issue-677-nested-ns-specifier.rs @@ -0,0 +1,20 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod foo { + #[allow(unused_imports)] + use self::super::super::root; + pub mod bar { + #[allow(unused_imports)] + use self::super::super::super::root; + pub type bar = ::std::os::raw::c_int; + } + } +} diff --git a/tests/expectations/tests/layout_array.rs b/tests/expectations/tests/layout_array.rs index 2cc8578519..0f9944e893 100644 --- a/tests/expectations/tests/layout_array.rs +++ b/tests/expectations/tests/layout_array.rs @@ -10,7 +10,9 @@ pub const RTE_MEMPOOL_MAX_OPS_IDX: ::std::os::raw::c_uint = 16; pub const RTE_HEAP_NUM_FREELISTS: ::std::os::raw::c_uint = 13; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct rte_mempool([u8; 0]); +pub struct rte_mempool { + _unused: [u8; 0], +} /** * Prototype for implementation specific data provisioning function. * diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs index 8e64fa2237..86d5e89247 100644 --- a/tests/expectations/tests/namespace.rs +++ b/tests/expectations/tests/namespace.rs @@ -69,6 +69,7 @@ pub mod root { pub m_c: T, pub m_c_ptr: *mut T, pub m_c_arr: [T; 10usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for C { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -81,6 +82,7 @@ pub mod root { #[derive(Debug)] pub struct D { pub m_c: root::C, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for D { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/nsStyleAutoArray.rs b/tests/expectations/tests/nsStyleAutoArray.rs index bc5f5184cb..04f01c0c3d 100644 --- a/tests/expectations/tests/nsStyleAutoArray.rs +++ b/tests/expectations/tests/nsStyleAutoArray.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct nsTArray { pub mBuff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for nsTArray { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for nsTArray { pub struct nsStyleAutoArray { pub mFirstElement: T, pub mOtherElements: nsTArray, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(i32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/tests/expectations/tests/replace_template_alias.rs b/tests/expectations/tests/replace_template_alias.rs index dbd0d283de..65a5332b9a 100644 --- a/tests/expectations/tests/replace_template_alias.rs +++ b/tests/expectations/tests/replace_template_alias.rs @@ -12,6 +12,7 @@ pub type JS_detail_MaybeWrapped = T; #[derive(Debug, Copy, Clone)] pub struct JS_Rooted { pub ptr: JS_detail_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for JS_Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/replaces_double.rs b/tests/expectations/tests/replaces_double.rs index 99b812db39..f7093d3d65 100644 --- a/tests/expectations/tests/replaces_double.rs +++ b/tests/expectations/tests/replaces_double.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: Rooted_MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } /** *
diff --git a/tests/expectations/tests/same_struct_name_in_different_namespaces.rs b/tests/expectations/tests/same_struct_name_in_different_namespaces.rs index 820b5e71e0..6ea051433d 100644 --- a/tests/expectations/tests/same_struct_name_in_different_namespaces.rs +++ b/tests/expectations/tests/same_struct_name_in_different_namespaces.rs @@ -6,7 +6,9 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct JS_Zone([u8; 0]); +pub struct JS_Zone { + _unused: [u8; 0], +} #[repr(C)] #[derive(Debug, Default, Copy)] pub struct JS_shadow_Zone { diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs index 494001f771..a36d729a4e 100644 --- a/tests/expectations/tests/template-param-usage-0.rs +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs index 95d200b576..d41740cd7a 100644 --- a/tests/expectations/tests/template-param-usage-10.rs +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -8,6 +8,8 @@ #[derive(Debug, Copy, Clone)] pub struct DoublyIndirectUsage { pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type DoublyIndirectUsage_Aliased = T; pub type DoublyIndirectUsage_Typedefed = U; @@ -16,6 +18,8 @@ pub type DoublyIndirectUsage_Typedefed = U; pub struct DoublyIndirectUsage_IndirectUsage { pub member: DoublyIndirectUsage_Aliased, pub another: DoublyIndirectUsage_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoublyIndirectUsage_IndirectUsage { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs index 0c31111e78..fcf10615f0 100644 --- a/tests/expectations/tests/template-param-usage-12.rs +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct BaseUsesT { pub t: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for BaseUsesT { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -17,6 +18,7 @@ impl Default for BaseUsesT { pub struct CrtpUsesU { pub _base: BaseUsesT>, pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for CrtpUsesU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs index c77da0973e..10e45ed1f0 100644 --- a/tests/expectations/tests/template-param-usage-13.rs +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -14,6 +14,7 @@ pub struct BaseIgnoresT { pub struct CrtpUsesU { pub _base: BaseIgnoresT, pub usage: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for CrtpUsesU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs index a653e08904..77667b454f 100644 --- a/tests/expectations/tests/template-param-usage-15.rs +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct BaseUsesT { pub usage: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for BaseUsesT { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs index 6dc21b6865..4f5987a105 100644 --- a/tests/expectations/tests/template-param-usage-2.rs +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -8,11 +8,13 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { pub also: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs index a7ff22f900..07571dcc45 100644 --- a/tests/expectations/tests/template-param-usage-3.rs +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -8,12 +8,15 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { pub also: T, pub more: U, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs index 31f8872dbb..7b8fe9f1ec 100644 --- a/tests/expectations/tests/template-param-usage-4.rs +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct UsesTemplateParameter { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs index 5a9caf32d0..3efdfac339 100644 --- a/tests/expectations/tests/template-param-usage-5.rs +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -8,6 +8,7 @@ #[derive(Debug, Copy, Clone)] pub struct IndirectlyUsesTemplateParameter { pub aliased: IndirectlyUsesTemplateParameter_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type IndirectlyUsesTemplateParameter_Aliased = T; impl Default for IndirectlyUsesTemplateParameter { diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs index 2544ffd047..3d1378ad98 100644 --- a/tests/expectations/tests/template-param-usage-7.rs +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -9,6 +9,8 @@ pub struct DoesNotUseU { pub t: T, pub v: V, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoesNotUseU { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs index b181cc0911..322c725718 100644 --- a/tests/expectations/tests/template-param-usage-8.rs +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -9,6 +9,8 @@ pub struct IndirectUsage { pub member1: IndirectUsage_Typedefed, pub member2: IndirectUsage_Aliased, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } pub type IndirectUsage_Typedefed = T; pub type IndirectUsage_Aliased = U; diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs index d0a3f29f6a..5f2319c448 100644 --- a/tests/expectations/tests/template-param-usage-9.rs +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -16,6 +16,8 @@ pub type DoesNotUse_Typedefed = U; pub struct DoesNotUse_IndirectUsage { pub member: DoesNotUse_Aliased, pub another: DoesNotUse_Typedefed, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for DoesNotUse_IndirectUsage { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 911b0e6ae1..682c6db9c1 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -10,6 +10,7 @@ pub struct Foo { pub m_member: T, pub m_member_ptr: *mut T, pub m_member_arr: [T; 1usize], + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Foo { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -29,6 +30,7 @@ pub type D_MyFoo = Foo<::std::os::raw::c_int>; pub struct D_U { pub m_nested_foo: D_MyFoo, pub m_baz: Z, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for D_U { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -42,6 +44,7 @@ pub struct Rooted { pub prev: *mut T, pub next: *mut Rooted<*mut ::std::os::raw::c_void>, pub ptr: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -73,6 +76,7 @@ impl Default for RootedContainer { #[derive(Debug)] pub struct WithDtor { pub member: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for WithDtor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -133,6 +137,7 @@ impl Clone for POD { #[derive(Debug, Copy, Clone)] pub struct NestedReplaced { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedReplaced { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -141,6 +146,7 @@ impl Default for NestedReplaced { #[derive(Debug, Copy, Clone)] pub struct NestedBase { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedBase { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -149,6 +155,7 @@ impl Default for NestedBase { #[derive(Debug, Copy, Clone)] pub struct Incomplete { pub d: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Incomplete { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -159,6 +166,7 @@ pub struct NestedContainer { pub c: T, pub nested: NestedReplaced, pub inc: Incomplete, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for NestedContainer { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -193,6 +201,7 @@ pub struct Templated { #[derive(Debug)] pub struct ReplacedWithoutDestructor { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ReplacedWithoutDestructor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -201,6 +210,7 @@ impl Default for ReplacedWithoutDestructor { #[derive(Debug)] pub struct ShouldNotBeCopiable { pub m_member: ReplacedWithoutDestructor, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ShouldNotBeCopiable { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -209,6 +219,7 @@ impl Default for ShouldNotBeCopiable { #[derive(Debug)] pub struct ShouldNotBeCopiableAsWell { pub m_member: ReplacedWithoutDestructorFwd, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ShouldNotBeCopiableAsWell { fn default() -> Self { unsafe { ::std::mem::zeroed() } } @@ -223,6 +234,7 @@ impl Default for ShouldNotBeCopiableAsWell { #[derive(Debug)] pub struct ReplacedWithoutDestructorFwd { pub buff: *mut T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for ReplacedWithoutDestructorFwd { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_alias.rs b/tests/expectations/tests/template_alias.rs index 44f7830f66..f98d165df8 100644 --- a/tests/expectations/tests/template_alias.rs +++ b/tests/expectations/tests/template_alias.rs @@ -9,6 +9,7 @@ pub type JS_detail_Wrapped = T; #[derive(Debug, Copy, Clone)] pub struct JS_Rooted { pub ptr: JS_detail_Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for JS_Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_alias_namespace.rs b/tests/expectations/tests/template_alias_namespace.rs index 90740a2d6f..491bb68cad 100644 --- a/tests/expectations/tests/template_alias_namespace.rs +++ b/tests/expectations/tests/template_alias_namespace.rs @@ -20,6 +20,7 @@ pub mod root { #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: root::JS::detail::Wrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index 265ab5ce1f..5f6b4c38db 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -13,6 +13,7 @@ pub struct Wrapper { #[derive(Debug, Copy, Clone)] pub struct Wrapper_Wrapped { pub t: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Wrapper_Wrapped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/test_multiple_header_calls_in_builder.rs b/tests/expectations/tests/test_multiple_header_calls_in_builder.rs new file mode 100644 index 0000000000..58ec6fff09 --- /dev/null +++ b/tests/expectations/tests/test_multiple_header_calls_in_builder.rs @@ -0,0 +1,17 @@ +/* automatically generated by rust-bindgen */ + +extern "C" { + #[link_name = "foo"] + pub static mut foo: + ::std::option::Option ::std::os::raw::c_int>; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = 0, Qux = 1, } +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Neg { MinusOne = -1, One = 1, } diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs index 2e0f2f4d6c..09c3248621 100644 --- a/tests/expectations/tests/type_alias_partial_template_especialization.rs +++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs @@ -9,6 +9,7 @@ pub type MaybeWrapped
= A; #[derive(Debug, Copy, Clone)] pub struct Rooted { pub ptr: MaybeWrapped, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/using.rs b/tests/expectations/tests/using.rs index 1638287ab6..44376b93a9 100644 --- a/tests/expectations/tests/using.rs +++ b/tests/expectations/tests/using.rs @@ -9,6 +9,7 @@ pub struct Point { pub x: T, pub y: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for Point { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index e5194c02c6..fa56f04b6d 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -25,6 +25,7 @@ pub type Float = f32; pub struct PointTyped { pub x: F, pub y: F, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for PointTyped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index 8af4aba352..a83f02735b 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -9,11 +9,13 @@ pub struct WhitelistMe { pub foo: ::std::os::raw::c_int, pub bar: WhitelistMe_Inner, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct WhitelistMe_Inner { pub bar: T, + _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, } impl Default for WhitelistMe_Inner { fn default() -> Self { unsafe { ::std::mem::zeroed() } } diff --git a/tests/headers/issue-639-typedef-anon-field.hpp b/tests/headers/issue-639-typedef-anon-field.hpp new file mode 100644 index 0000000000..efd6c4f40a --- /dev/null +++ b/tests/headers/issue-639-typedef-anon-field.hpp @@ -0,0 +1,15 @@ +class Foo { + public: + typedef struct { + int abc; + } Bar; + + Bar bar; +}; + +class Baz { + public: + typedef struct { + int abc; + } Bar; +}; diff --git a/tests/headers/issue-643-inner-struct.h b/tests/headers/issue-643-inner-struct.h new file mode 100644 index 0000000000..25c525b357 --- /dev/null +++ b/tests/headers/issue-643-inner-struct.h @@ -0,0 +1,13 @@ +struct rte_ring { + struct rte_memzone *memzone; + + struct prod { + unsigned watermark; + } prod; + + struct cons { + unsigned sc_dequeue; + } cons; + + void *ring[]; +}; diff --git a/tests/headers/issue-645-cannot-find-type-T-in-this-scope.hpp b/tests/headers/issue-645-cannot-find-type-T-in-this-scope.hpp new file mode 100644 index 0000000000..f817f34dce --- /dev/null +++ b/tests/headers/issue-645-cannot-find-type-T-in-this-scope.hpp @@ -0,0 +1,9 @@ +// bindgen-flags: --blacklist-type RefPtr --raw-line "#[derive(Clone, Copy, Debug)] pub struct RefPtr(T);" --whitelist-type "HasRefPtr" -- -std=c++14 + +template class RefPtr {}; + +template +class HasRefPtr { + typedef T TypedefOfT; + RefPtr refptr_member; +}; diff --git a/tests/headers/issue-654-struct-fn-collision.h b/tests/headers/issue-654-struct-fn-collision.h new file mode 100644 index 0000000000..f52a1b200c --- /dev/null +++ b/tests/headers/issue-654-struct-fn-collision.h @@ -0,0 +1,2 @@ +struct foo; +int foo(void); diff --git a/tests/headers/issue-662-cannot-find-T-in-this-scope.hpp b/tests/headers/issue-662-cannot-find-T-in-this-scope.hpp new file mode 100644 index 0000000000..6b3f928b0b --- /dev/null +++ b/tests/headers/issue-662-cannot-find-T-in-this-scope.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: -- --std=c++14 + +template class RefPtr { T a; }; +template class nsMainThreadPtrHolder { T a; }; +template class nsMainThreadPtrHandle { + RefPtr> mPtr; +}; diff --git a/tests/headers/issue-662-part-2.hpp b/tests/headers/issue-662-part-2.hpp new file mode 100644 index 0000000000..84edb39778 --- /dev/null +++ b/tests/headers/issue-662-part-2.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: --blacklist-type RefPtr --raw-line '#[derive(Clone, Copy, Debug)] pub struct RefPtr(T);' -- --std=c++14 + +// This is pretty much the same as the other issue 662 test case, but this time +// we blacklist RefPtr to exercise the instantiation-of-a-blacklisted-template +// path in the template analysis. + +template class RefPtr {}; +template class nsMainThreadPtrHolder { T a; }; +template class nsMainThreadPtrHandle { + RefPtr> mPtr; +}; diff --git a/tests/headers/issue-674-1.hpp b/tests/headers/issue-674-1.hpp new file mode 100644 index 0000000000..f5c0591750 --- /dev/null +++ b/tests/headers/issue-674-1.hpp @@ -0,0 +1,8 @@ +// bindgen-flags: --enable-cxx-namespaces --whitelist-type CapturingContentInfo --opaque-type 'mozilla::Maybe' -- -- -std=c++14 + +namespace mozilla { +template class Maybe { using ValueType = T; }; +} +struct CapturingContentInfo { + mozilla::Maybe a; +}; diff --git a/tests/headers/issue-674-2.hpp b/tests/headers/issue-674-2.hpp new file mode 100644 index 0000000000..5f65a05bdc --- /dev/null +++ b/tests/headers/issue-674-2.hpp @@ -0,0 +1,15 @@ +// bindgen-flags: --enable-cxx-namespaces --whitelist-type StaticRefPtr --opaque-type 'JS::Rooted' -- -- -std=c++14 + +namespace JS { +template class Rooted { using ElementType = T; }; +} +class c { + JS::Rooted b; +}; +class B { + c a; +}; +template class StaticRefPtr {}; +struct { + StaticRefPtr d; +} e; diff --git a/tests/headers/issue-674-3.hpp b/tests/headers/issue-674-3.hpp new file mode 100644 index 0000000000..c1bd2f32db --- /dev/null +++ b/tests/headers/issue-674-3.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: --enable-cxx-namespaces --whitelist-type nsCSSValue --opaque-type 'nsRefPtrHashtable' -- -- -std=c++14 + +template class nsRefPtrHashtable { + typedef PtrType *UserDataType; +}; +struct a { + nsRefPtrHashtable b; +}; +class nsCSSValue { + a c; +}; diff --git a/tests/headers/issue-677-nested-ns-specifier.hpp b/tests/headers/issue-677-nested-ns-specifier.hpp new file mode 100644 index 0000000000..ef2cea82dc --- /dev/null +++ b/tests/headers/issue-677-nested-ns-specifier.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --enable-cxx-namespaces -- -std=c++14 + +namespace foo::bar { + typedef int bar; +} diff --git a/tests/stylo_sanity.rs b/tests/stylo_sanity.rs index d925cb33c0..c75d65a4c2 100755 --- a/tests/stylo_sanity.rs +++ b/tests/stylo_sanity.rs @@ -1,547 +1,548 @@ -extern crate bindgen; - -/// A sanity test that we can generate bindings for Stylo. -/// -/// We don't assert on expected output because its just too big. The output will -/// change too often, and it won't be clear what is going on at a glance, unlike -/// the other tests with smaller input headers. -/// -/// This test is relatively slow, so we also only run it in release mode. -/// -/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing -/// how long bindings generation takes for Stylo. Stylo bindings generation -/// takes too long to be a proper `#[bench]`. -#[test] -#[cfg(not(any(debug_assertions, - feature = "testing_only_extra_assertions", - feature = "testing_only_llvm_stable")))] -fn sanity_check_can_generate_stylo_bindings() { - use std::time::Instant; - - let then = Instant::now(); - - bindgen::builder() - .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) - .whitelisted_function("Servo_.*") - .whitelisted_function("Gecko_.*") - .hide_type("nsACString_internal") - .hide_type("nsAString_internal") - .hide_type("mozilla::css::URLValue") - .hide_type("RawGeckoAnimationPropertySegment") - .hide_type("RawGeckoComputedTiming") - .hide_type("RawGeckoDocument") - .hide_type("RawGeckoElement") - .hide_type("RawGeckoKeyframeList") - .hide_type("RawGeckoComputedKeyframeValuesList") - .hide_type("RawGeckoFontFaceRuleList") - .hide_type("RawGeckoNode") - .hide_type("RawGeckoAnimationValueList") - .hide_type("RawServoAnimationValue") - .hide_type("RawServoAnimationValueMap") - .hide_type("RawServoDeclarationBlock") - .hide_type("RawGeckoPresContext") - .hide_type("RawGeckoPresContextOwned") - .hide_type("RawGeckoStyleAnimationList") - .hide_type("RawGeckoURLExtraData") - .hide_type("RefPtr") - .hide_type("CSSPseudoClassType") - .hide_type("TraversalRootBehavior") - .hide_type("ComputedTimingFunction_BeforeFlag") - .hide_type("FontFamilyList") - .hide_type("FontFamilyType") - .hide_type("Keyframe") - .hide_type("ServoBundledURI") - .hide_type("ServoElementSnapshot") - .hide_type("SheetParsingMode") - .hide_type("StyleBasicShape") - .hide_type("StyleBasicShapeType") - .hide_type("StyleShapeSource") - .hide_type("nsCSSFontFaceRule") - .hide_type("nsCSSKeyword") - .hide_type("nsCSSPropertyID") - .hide_type("nsCSSShadowArray") - .hide_type("nsCSSUnit") - .hide_type("nsCSSValue") - .hide_type("nsCSSValueSharedList") - .hide_type("nsChangeHint") - .hide_type("nsCursorImage") - .hide_type("nsFont") - .hide_type("nsIAtom") - .hide_type("nsMediaFeature") - .hide_type("nsRestyleHint") - .hide_type("nsStyleBackground") - .hide_type("nsStyleBorder") - .hide_type("nsStyleColor") - .hide_type("nsStyleColumn") - .hide_type("nsStyleContent") - .hide_type("nsStyleContentData") - .hide_type("nsStyleContentType") - .hide_type("nsStyleContext") - .hide_type("nsStyleCoord") - .hide_type("nsStyleCoord_Calc") - .hide_type("nsStyleCoord_CalcValue") - .hide_type("nsStyleDisplay") - .hide_type("nsStyleEffects") - .hide_type("nsStyleFilter") - .hide_type("nsStyleFont") - .hide_type("nsStyleGradient") - .hide_type("nsStyleGradientStop") - .hide_type("nsStyleImage") - .hide_type("nsStyleImageLayers") - .hide_type("nsStyleImageLayers_Layer") - .hide_type("nsStyleImageLayers_LayerType") - .hide_type("nsStyleImageRequest") - .hide_type("nsStyleList") - .hide_type("nsStyleMargin") - .hide_type("nsStyleOutline") - .hide_type("nsStylePadding") - .hide_type("nsStylePosition") - .hide_type("nsStyleQuoteValues") - .hide_type("nsStyleSVG") - .hide_type("nsStyleSVGPaint") - .hide_type("nsStyleSVGReset") - .hide_type("nsStyleTable") - .hide_type("nsStyleTableBorder") - .hide_type("nsStyleText") - .hide_type("nsStyleTextReset") - .hide_type("nsStyleUIReset") - .hide_type("nsStyleUnion") - .hide_type("nsStyleUnit") - .hide_type("nsStyleUserInterface") - .hide_type("nsStyleVariables") - .hide_type("nsStyleVisibility") - .hide_type("nsStyleXUL") - .hide_type("nsTimingFunction") - .hide_type("nscolor") - .hide_type("nscoord") - .hide_type("nsresult") - .hide_type("Loader") - .hide_type("ServoStyleSheet") - .hide_type("EffectCompositor_CascadeLevel") - .hide_type("UpdateAnimationsTasks") - .hide_type("nsTArrayBorrowed_uintptr_t") - .hide_type("ServoCssRulesStrong") - .hide_type("ServoCssRulesBorrowed") - .hide_type("ServoCssRulesBorrowedOrNull") - .hide_type("ServoCssRules") - .hide_type("RawServoStyleSheetStrong") - .hide_type("RawServoStyleSheetBorrowed") - .hide_type("RawServoStyleSheetBorrowedOrNull") - .hide_type("RawServoStyleSheet") - .hide_type("ServoComputedValuesStrong") - .hide_type("ServoComputedValuesBorrowed") - .hide_type("ServoComputedValuesBorrowedOrNull") - .hide_type("ServoComputedValues") - .hide_type("RawServoDeclarationBlockStrong") - .hide_type("RawServoDeclarationBlockBorrowed") - .hide_type("RawServoDeclarationBlockBorrowedOrNull") - .hide_type("RawServoStyleRuleStrong") - .hide_type("RawServoStyleRuleBorrowed") - .hide_type("RawServoStyleRuleBorrowedOrNull") - .hide_type("RawServoStyleRule") - .hide_type("RawServoImportRuleStrong") - .hide_type("RawServoImportRuleBorrowed") - .hide_type("RawServoImportRuleBorrowedOrNull") - .hide_type("RawServoImportRule") - .hide_type("RawServoAnimationValueStrong") - .hide_type("RawServoAnimationValueBorrowed") - .hide_type("RawServoAnimationValueBorrowedOrNull") - .hide_type("RawServoAnimationValueMapStrong") - .hide_type("RawServoAnimationValueMapBorrowed") - .hide_type("RawServoAnimationValueMapBorrowedOrNull") - .hide_type("RawServoMediaListStrong") - .hide_type("RawServoMediaListBorrowed") - .hide_type("RawServoMediaListBorrowedOrNull") - .hide_type("RawServoMediaList") - .hide_type("RawServoMediaRuleStrong") - .hide_type("RawServoMediaRuleBorrowed") - .hide_type("RawServoMediaRuleBorrowedOrNull") - .hide_type("RawServoMediaRule") - .hide_type("RawServoNamespaceRuleStrong") - .hide_type("RawServoNamespaceRuleBorrowed") - .hide_type("RawServoNamespaceRuleBorrowedOrNull") - .hide_type("RawServoNamespaceRule") - .hide_type("RawServoStyleSetOwned") - .hide_type("RawServoStyleSetOwnedOrNull") - .hide_type("RawServoStyleSetBorrowed") - .hide_type("RawServoStyleSetBorrowedOrNull") - .hide_type("RawServoStyleSetBorrowedMut") - .hide_type("RawServoStyleSetBorrowedMutOrNull") - .hide_type("RawServoStyleSet") - .hide_type("StyleChildrenIteratorOwned") - .hide_type("StyleChildrenIteratorOwnedOrNull") - .hide_type("StyleChildrenIteratorBorrowed") - .hide_type("StyleChildrenIteratorBorrowedOrNull") - .hide_type("StyleChildrenIteratorBorrowedMut") - .hide_type("StyleChildrenIteratorBorrowedMutOrNull") - .hide_type("StyleChildrenIterator") - .hide_type("ServoElementSnapshotOwned") - .hide_type("ServoElementSnapshotOwnedOrNull") - .hide_type("ServoElementSnapshotBorrowed") - .hide_type("ServoElementSnapshotBorrowedOrNull") - .hide_type("ServoElementSnapshotBorrowedMut") - .hide_type("ServoElementSnapshotBorrowedMutOrNull") - .hide_type("RawGeckoNodeBorrowed") - .hide_type("RawGeckoNodeBorrowedOrNull") - .hide_type("RawGeckoElementBorrowed") - .hide_type("RawGeckoElementBorrowedOrNull") - .hide_type("RawGeckoDocumentBorrowed") - .hide_type("RawGeckoDocumentBorrowedOrNull") - .hide_type("RawServoDeclarationBlockStrongBorrowed") - .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") - .hide_type("RawGeckoPresContextBorrowed") - .hide_type("RawGeckoPresContextBorrowedOrNull") - .hide_type("RawGeckoStyleAnimationListBorrowed") - .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") - .hide_type("nsCSSValueBorrowed") - .hide_type("nsCSSValueBorrowedOrNull") - .hide_type("nsCSSValueBorrowedMut") - .hide_type("nsCSSValueBorrowedMutOrNull") - .hide_type("nsTimingFunctionBorrowed") - .hide_type("nsTimingFunctionBorrowedOrNull") - .hide_type("nsTimingFunctionBorrowedMut") - .hide_type("nsTimingFunctionBorrowedMutOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowed") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") - .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") - .hide_type("RawGeckoAnimationValueListBorrowed") - .hide_type("RawGeckoAnimationValueListBorrowedOrNull") - .hide_type("RawGeckoAnimationValueListBorrowedMut") - .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") - .hide_type("RawGeckoComputedTimingBorrowed") - .hide_type("RawGeckoComputedTimingBorrowedOrNull") - .hide_type("RawGeckoComputedTimingBorrowedMut") - .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") - .hide_type("RawGeckoKeyframeListBorrowed") - .hide_type("RawGeckoKeyframeListBorrowedOrNull") - .hide_type("RawGeckoKeyframeListBorrowedMut") - .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") - .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowed") - .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") - .hide_type("RawGeckoFontFaceRuleListBorrowedMut") - .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") - .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) - .raw_line(r#"type nsACString_internal = nsACString;"#) - .raw_line(r#"type nsAString_internal = nsAString;"#) - .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) - .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) - .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) - .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) - .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) - .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) - .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) - .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) - .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) - .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) - .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) - .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) - .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) - .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) - .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) - .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) - .raw_line(r#"use gecko_bindings::structs::nsFont;"#) - .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) - .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) - .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) - .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) - .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) - .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) - .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) - .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) - .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) - .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) - .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) - .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) - .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) - .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) - .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) - .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) - .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) - .raw_line(r#"unsafe impl Send for nsStyleList {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) - .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) - .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) - .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) - .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) - .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) - .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) - .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) - .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) - .raw_line(r#"unsafe impl Send for nsStyleText {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) - .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) - .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) - .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) - .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) - .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) - .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) - .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) - .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) - .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) - .raw_line(r#"use gecko_bindings::structs::nscolor;"#) - .raw_line(r#"use gecko_bindings::structs::nscoord;"#) - .raw_line(r#"use gecko_bindings::structs::nsresult;"#) - .raw_line(r#"use gecko_bindings::structs::Loader;"#) - .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) - .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) - .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) - .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) - .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) - .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) - .raw_line(r#"enum ServoCssRulesVoid { }"#) - .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) - .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) - .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) - .raw_line(r#"enum RawServoStyleSheetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) - .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) - .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) - .raw_line(r#"enum ServoComputedValuesVoid { }"#) - .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) - .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) - .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) - .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) - .raw_line(r#"enum RawServoStyleRuleVoid { }"#) - .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) - .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) - .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) - .raw_line(r#"enum RawServoImportRuleVoid { }"#) - .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) - .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) - .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) - .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) - .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) - .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) - .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) - .raw_line(r#"enum RawServoMediaListVoid { }"#) - .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) - .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) - .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) - .raw_line(r#"enum RawServoMediaRuleVoid { }"#) - .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) - .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) - .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) - .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) - .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) - .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) - .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) - .raw_line(r#"enum RawServoStyleSetVoid { }"#) - .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) - .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) - .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) - .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) - .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) - .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) - .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) - .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) - .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) - .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) - .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) - .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) - .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) - .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) - .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) - .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) - .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) - .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) - .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) - .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) - .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) - .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) - .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) - .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) - .clang_arg("-x") - .clang_arg("c++") - .clang_arg("-std=c++14") - .clang_arg("-DTRACING=1") - .clang_arg("-DIMPL_LIBXUL") - .clang_arg("-DMOZ_STYLO_BINDINGS=1") - .clang_arg("-DMOZILLA_INTERNAL_API") - .clang_arg("-DRUST_BINDGEN") - .clang_arg("-DMOZ_STYLO") - .clang_arg("-DOS_POSIX=1") - .clang_arg("-DOS_LINUX=1") - .generate() - .expect("Should generate stylo bindings"); - - let now = Instant::now(); - - println!(""); - println!(""); - println!("Generated Stylo bindings in: {:?}", now.duration_since(then)); - println!(""); - println!(""); - - // panic!("Uncomment this line to get timing logs"); -} +extern crate bindgen; + +/// A sanity test that we can generate bindings for Stylo. +/// +/// We don't assert on expected output because its just too big. The output will +/// change too often, and it won't be clear what is going on at a glance, unlike +/// the other tests with smaller input headers. +/// +/// This test is relatively slow, so we also only run it in release mode. +/// +/// Finally, uncomment the `panic!` at the bottom of the test to get logs timing +/// how long bindings generation takes for Stylo. Stylo bindings generation +/// takes too long to be a proper `#[bench]`. +#[test] +#[cfg(not(any(debug_assertions, + feature = "testing_only_extra_assertions", + feature = "testing_only_llvm_stable")))] +fn sanity_check_can_generate_stylo_bindings() { + use std::time::Instant; + + let then = Instant::now(); + + bindgen::builder() + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/stylo.hpp")) + .whitelisted_function("Servo_.*") + .whitelisted_function("Gecko_.*") + .hide_type("nsACString_internal") + .hide_type("nsAString_internal") + .hide_type("mozilla::css::URLValue") + .hide_type("RawGeckoAnimationPropertySegment") + .hide_type("RawGeckoComputedTiming") + .hide_type("RawGeckoDocument") + .hide_type("RawGeckoElement") + .hide_type("RawGeckoKeyframeList") + .hide_type("RawGeckoComputedKeyframeValuesList") + .hide_type("RawGeckoFontFaceRuleList") + .hide_type("RawGeckoNode") + .hide_type("RawGeckoAnimationValueList") + .hide_type("RawServoAnimationValue") + .hide_type("RawServoAnimationValueMap") + .hide_type("RawServoDeclarationBlock") + .hide_type("RawGeckoPresContext") + .hide_type("RawGeckoPresContextOwned") + .hide_type("RawGeckoStyleAnimationList") + .hide_type("RawGeckoURLExtraData") + .hide_type("RefPtr") + .hide_type("CSSPseudoClassType") + .hide_type("TraversalRootBehavior") + .hide_type("ComputedTimingFunction_BeforeFlag") + .hide_type("FontFamilyList") + .hide_type("FontFamilyType") + .hide_type("Keyframe") + .hide_type("ServoBundledURI") + .hide_type("ServoElementSnapshot") + .hide_type("SheetParsingMode") + .hide_type("StyleBasicShape") + .hide_type("StyleBasicShapeType") + .hide_type("StyleShapeSource") + .hide_type("nsCSSFontFaceRule") + .hide_type("nsCSSKeyword") + .hide_type("nsCSSPropertyID") + .hide_type("nsCSSShadowArray") + .hide_type("nsCSSUnit") + .hide_type("nsCSSValue") + .hide_type("nsCSSValueSharedList") + .hide_type("nsChangeHint") + .hide_type("nsCursorImage") + .hide_type("nsFont") + .hide_type("nsIAtom") + .hide_type("nsMediaFeature") + .hide_type("nsRestyleHint") + .hide_type("nsStyleBackground") + .hide_type("nsStyleBorder") + .hide_type("nsStyleColor") + .hide_type("nsStyleColumn") + .hide_type("nsStyleContent") + .hide_type("nsStyleContentData") + .hide_type("nsStyleContentType") + .hide_type("nsStyleContext") + .hide_type("nsStyleCoord") + .hide_type("nsStyleCoord_Calc") + .hide_type("nsStyleCoord_CalcValue") + .hide_type("nsStyleDisplay") + .hide_type("nsStyleEffects") + .hide_type("nsStyleFilter") + .hide_type("nsStyleFont") + .hide_type("nsStyleGradient") + .hide_type("nsStyleGradientStop") + .hide_type("nsStyleImage") + .hide_type("nsStyleImageLayers") + .hide_type("nsStyleImageLayers_Layer") + .hide_type("nsStyleImageLayers_LayerType") + .hide_type("nsStyleImageRequest") + .hide_type("nsStyleList") + .hide_type("nsStyleMargin") + .hide_type("nsStyleOutline") + .hide_type("nsStylePadding") + .hide_type("nsStylePosition") + .hide_type("nsStyleQuoteValues") + .hide_type("nsStyleSVG") + .hide_type("nsStyleSVGPaint") + .hide_type("nsStyleSVGReset") + .hide_type("nsStyleTable") + .hide_type("nsStyleTableBorder") + .hide_type("nsStyleText") + .hide_type("nsStyleTextReset") + .hide_type("nsStyleUIReset") + .hide_type("nsStyleUnion") + .hide_type("nsStyleUnit") + .hide_type("nsStyleUserInterface") + .hide_type("nsStyleVariables") + .hide_type("nsStyleVisibility") + .hide_type("nsStyleXUL") + .hide_type("nsTimingFunction") + .hide_type("nscolor") + .hide_type("nscoord") + .hide_type("nsresult") + .hide_type("Loader") + .hide_type("ServoStyleSheet") + .hide_type("EffectCompositor_CascadeLevel") + .hide_type("UpdateAnimationsTasks") + .hide_type("nsTArrayBorrowed_uintptr_t") + .hide_type("ServoCssRulesStrong") + .hide_type("ServoCssRulesBorrowed") + .hide_type("ServoCssRulesBorrowedOrNull") + .hide_type("ServoCssRules") + .hide_type("RawServoStyleSheetStrong") + .hide_type("RawServoStyleSheetBorrowed") + .hide_type("RawServoStyleSheetBorrowedOrNull") + .hide_type("RawServoStyleSheet") + .hide_type("ServoComputedValuesStrong") + .hide_type("ServoComputedValuesBorrowed") + .hide_type("ServoComputedValuesBorrowedOrNull") + .hide_type("ServoComputedValues") + .hide_type("RawServoDeclarationBlockStrong") + .hide_type("RawServoDeclarationBlockBorrowed") + .hide_type("RawServoDeclarationBlockBorrowedOrNull") + .hide_type("RawServoStyleRuleStrong") + .hide_type("RawServoStyleRuleBorrowed") + .hide_type("RawServoStyleRuleBorrowedOrNull") + .hide_type("RawServoStyleRule") + .hide_type("RawServoImportRuleStrong") + .hide_type("RawServoImportRuleBorrowed") + .hide_type("RawServoImportRuleBorrowedOrNull") + .hide_type("RawServoImportRule") + .hide_type("RawServoAnimationValueStrong") + .hide_type("RawServoAnimationValueBorrowed") + .hide_type("RawServoAnimationValueBorrowedOrNull") + .hide_type("RawServoAnimationValueMapStrong") + .hide_type("RawServoAnimationValueMapBorrowed") + .hide_type("RawServoAnimationValueMapBorrowedOrNull") + .hide_type("RawServoMediaListStrong") + .hide_type("RawServoMediaListBorrowed") + .hide_type("RawServoMediaListBorrowedOrNull") + .hide_type("RawServoMediaList") + .hide_type("RawServoMediaRuleStrong") + .hide_type("RawServoMediaRuleBorrowed") + .hide_type("RawServoMediaRuleBorrowedOrNull") + .hide_type("RawServoMediaRule") + .hide_type("RawServoNamespaceRuleStrong") + .hide_type("RawServoNamespaceRuleBorrowed") + .hide_type("RawServoNamespaceRuleBorrowedOrNull") + .hide_type("RawServoNamespaceRule") + .hide_type("RawServoStyleSetOwned") + .hide_type("RawServoStyleSetOwnedOrNull") + .hide_type("RawServoStyleSetBorrowed") + .hide_type("RawServoStyleSetBorrowedOrNull") + .hide_type("RawServoStyleSetBorrowedMut") + .hide_type("RawServoStyleSetBorrowedMutOrNull") + .hide_type("RawServoStyleSet") + .hide_type("StyleChildrenIteratorOwned") + .hide_type("StyleChildrenIteratorOwnedOrNull") + .hide_type("StyleChildrenIteratorBorrowed") + .hide_type("StyleChildrenIteratorBorrowedOrNull") + .hide_type("StyleChildrenIteratorBorrowedMut") + .hide_type("StyleChildrenIteratorBorrowedMutOrNull") + .hide_type("StyleChildrenIterator") + .hide_type("ServoElementSnapshotOwned") + .hide_type("ServoElementSnapshotOwnedOrNull") + .hide_type("ServoElementSnapshotBorrowed") + .hide_type("ServoElementSnapshotBorrowedOrNull") + .hide_type("ServoElementSnapshotBorrowedMut") + .hide_type("ServoElementSnapshotBorrowedMutOrNull") + .hide_type("RawGeckoNodeBorrowed") + .hide_type("RawGeckoNodeBorrowedOrNull") + .hide_type("RawGeckoElementBorrowed") + .hide_type("RawGeckoElementBorrowedOrNull") + .hide_type("RawGeckoDocumentBorrowed") + .hide_type("RawGeckoDocumentBorrowedOrNull") + .hide_type("RawServoDeclarationBlockStrongBorrowed") + .hide_type("RawServoDeclarationBlockStrongBorrowedOrNull") + .hide_type("RawGeckoPresContextBorrowed") + .hide_type("RawGeckoPresContextBorrowedOrNull") + .hide_type("RawGeckoStyleAnimationListBorrowed") + .hide_type("RawGeckoStyleAnimationListBorrowedOrNull") + .hide_type("nsCSSValueBorrowed") + .hide_type("nsCSSValueBorrowedOrNull") + .hide_type("nsCSSValueBorrowedMut") + .hide_type("nsCSSValueBorrowedMutOrNull") + .hide_type("nsTimingFunctionBorrowed") + .hide_type("nsTimingFunctionBorrowedOrNull") + .hide_type("nsTimingFunctionBorrowedMut") + .hide_type("nsTimingFunctionBorrowedMutOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowed") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedOrNull") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMut") + .hide_type("RawGeckoAnimationPropertySegmentBorrowedMutOrNull") + .hide_type("RawGeckoAnimationValueListBorrowed") + .hide_type("RawGeckoAnimationValueListBorrowedOrNull") + .hide_type("RawGeckoAnimationValueListBorrowedMut") + .hide_type("RawGeckoAnimationValueListBorrowedMutOrNull") + .hide_type("RawGeckoComputedTimingBorrowed") + .hide_type("RawGeckoComputedTimingBorrowedOrNull") + .hide_type("RawGeckoComputedTimingBorrowedMut") + .hide_type("RawGeckoComputedTimingBorrowedMutOrNull") + .hide_type("RawGeckoKeyframeListBorrowed") + .hide_type("RawGeckoKeyframeListBorrowedOrNull") + .hide_type("RawGeckoKeyframeListBorrowedMut") + .hide_type("RawGeckoKeyframeListBorrowedMutOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowed") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedOrNull") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMut") + .hide_type("RawGeckoComputedKeyframeValuesListBorrowedMutOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowed") + .hide_type("RawGeckoFontFaceRuleListBorrowedOrNull") + .hide_type("RawGeckoFontFaceRuleListBorrowedMut") + .hide_type("RawGeckoFontFaceRuleListBorrowedMutOrNull") + .raw_line(r#"pub use nsstring::{nsACString, nsAString, nsString};"#) + .raw_line(r#"type nsACString_internal = nsACString;"#) + .raw_line(r#"type nsAString_internal = nsAString;"#) + .raw_line(r#"use gecko_bindings::structs::mozilla::css::URLValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedTiming;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoDocument;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoElement;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoKeyframeList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoFontFaceRuleList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoNode;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoAnimationValueList;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValue;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoAnimationValueMap;"#) + .raw_line(r#"use gecko_bindings::structs::RawServoDeclarationBlock;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContext;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoPresContextOwned;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoStyleAnimationList;"#) + .raw_line(r#"use gecko_bindings::structs::RawGeckoURLExtraData;"#) + .raw_line(r#"use gecko_bindings::structs::RefPtr;"#) + .raw_line(r#"use gecko_bindings::structs::CSSPseudoClassType;"#) + .raw_line(r#"use gecko_bindings::structs::TraversalRootBehavior;"#) + .raw_line(r#"use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyList;"#) + .raw_line(r#"use gecko_bindings::structs::FontFamilyType;"#) + .raw_line(r#"use gecko_bindings::structs::Keyframe;"#) + .raw_line(r#"use gecko_bindings::structs::ServoBundledURI;"#) + .raw_line(r#"use gecko_bindings::structs::ServoElementSnapshot;"#) + .raw_line(r#"use gecko_bindings::structs::SheetParsingMode;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShape;"#) + .raw_line(r#"use gecko_bindings::structs::StyleBasicShapeType;"#) + .raw_line(r#"use gecko_bindings::structs::StyleShapeSource;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSFontFaceRule;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSKeyword;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSPropertyID;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSShadowArray;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSUnit;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValue;"#) + .raw_line(r#"use gecko_bindings::structs::nsCSSValueSharedList;"#) + .raw_line(r#"use gecko_bindings::structs::nsChangeHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsCursorImage;"#) + .raw_line(r#"use gecko_bindings::structs::nsFont;"#) + .raw_line(r#"use gecko_bindings::structs::nsIAtom;"#) + .raw_line(r#"use gecko_bindings::structs::nsMediaFeature;"#) + .raw_line(r#"use gecko_bindings::structs::nsRestyleHint;"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBackground;"#) + .raw_line(r#"unsafe impl Send for nsStyleBackground {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBackground {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColor;"#) + .raw_line(r#"unsafe impl Send for nsStyleColor {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColor {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleColumn;"#) + .raw_line(r#"unsafe impl Send for nsStyleColumn {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleColumn {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContent;"#) + .raw_line(r#"unsafe impl Send for nsStyleContent {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContent {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentData;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentData {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentData {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContentType;"#) + .raw_line(r#"unsafe impl Send for nsStyleContentType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContentType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleContext;"#) + .raw_line(r#"unsafe impl Send for nsStyleContext {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleContext {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_Calc;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_Calc {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_Calc {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleCoord_CalcValue;"#) + .raw_line(r#"unsafe impl Send for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleCoord_CalcValue {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleDisplay;"#) + .raw_line(r#"unsafe impl Send for nsStyleDisplay {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleDisplay {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleEffects;"#) + .raw_line(r#"unsafe impl Send for nsStyleEffects {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleEffects {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFilter;"#) + .raw_line(r#"unsafe impl Send for nsStyleFilter {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFilter {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleFont;"#) + .raw_line(r#"unsafe impl Send for nsStyleFont {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleFont {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradient;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradient {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradient {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleGradientStop;"#) + .raw_line(r#"unsafe impl Send for nsStyleGradientStop {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleGradientStop {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImage;"#) + .raw_line(r#"unsafe impl Send for nsStyleImage {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImage {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_Layer;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_Layer {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageLayers_LayerType;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageLayers_LayerType {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleImageRequest;"#) + .raw_line(r#"unsafe impl Send for nsStyleImageRequest {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleImageRequest {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleList;"#) + .raw_line(r#"unsafe impl Send for nsStyleList {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleList {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleMargin;"#) + .raw_line(r#"unsafe impl Send for nsStyleMargin {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleMargin {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleOutline;"#) + .raw_line(r#"unsafe impl Send for nsStyleOutline {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleOutline {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePadding;"#) + .raw_line(r#"unsafe impl Send for nsStylePadding {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePadding {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStylePosition;"#) + .raw_line(r#"unsafe impl Send for nsStylePosition {}"#) + .raw_line(r#"unsafe impl Sync for nsStylePosition {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleQuoteValues;"#) + .raw_line(r#"unsafe impl Send for nsStyleQuoteValues {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleQuoteValues {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVG;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVG {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVG {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGPaint;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGPaint {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGPaint {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleSVGReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleSVGReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleSVGReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTable;"#) + .raw_line(r#"unsafe impl Send for nsStyleTable {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTable {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTableBorder;"#) + .raw_line(r#"unsafe impl Send for nsStyleTableBorder {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTableBorder {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleText;"#) + .raw_line(r#"unsafe impl Send for nsStyleText {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleText {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleTextReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleTextReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleTextReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUIReset;"#) + .raw_line(r#"unsafe impl Send for nsStyleUIReset {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUIReset {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnion;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnion {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnion {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUnit;"#) + .raw_line(r#"unsafe impl Send for nsStyleUnit {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUnit {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleUserInterface;"#) + .raw_line(r#"unsafe impl Send for nsStyleUserInterface {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleUserInterface {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVariables;"#) + .raw_line(r#"unsafe impl Send for nsStyleVariables {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVariables {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleVisibility;"#) + .raw_line(r#"unsafe impl Send for nsStyleVisibility {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleVisibility {}"#) + .raw_line(r#"use gecko_bindings::structs::nsStyleXUL;"#) + .raw_line(r#"unsafe impl Send for nsStyleXUL {}"#) + .raw_line(r#"unsafe impl Sync for nsStyleXUL {}"#) + .raw_line(r#"use gecko_bindings::structs::nsTimingFunction;"#) + .raw_line(r#"use gecko_bindings::structs::nscolor;"#) + .raw_line(r#"use gecko_bindings::structs::nscoord;"#) + .raw_line(r#"use gecko_bindings::structs::nsresult;"#) + .raw_line(r#"use gecko_bindings::structs::Loader;"#) + .raw_line(r#"use gecko_bindings::structs::ServoStyleSheet;"#) + .raw_line(r#"use gecko_bindings::structs::EffectCompositor_CascadeLevel;"#) + .raw_line(r#"use gecko_bindings::structs::UpdateAnimationsTasks;"#) + .raw_line(r#"pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray;"#) + .raw_line(r#"pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;"#) + .raw_line(r#"pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;"#) + .raw_line(r#"enum ServoCssRulesVoid { }"#) + .raw_line(r#"pub struct ServoCssRules(ServoCssRulesVoid);"#) + .raw_line(r#"pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;"#) + .raw_line(r#"pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;"#) + .raw_line(r#"enum RawServoStyleSheetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSheet(RawServoStyleSheetVoid);"#) + .raw_line(r#"pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;"#) + .raw_line(r#"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;"#) + .raw_line(r#"enum ServoComputedValuesVoid { }"#) + .raw_line(r#"pub struct ServoComputedValues(ServoComputedValuesVoid);"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;"#) + .raw_line(r#"pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;"#) + .raw_line(r#"pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;"#) + .raw_line(r#"pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;"#) + .raw_line(r#"enum RawServoStyleRuleVoid { }"#) + .raw_line(r#"pub struct RawServoStyleRule(RawServoStyleRuleVoid);"#) + .raw_line(r#"pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;"#) + .raw_line(r#"pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;"#) + .raw_line(r#"enum RawServoImportRuleVoid { }"#) + .raw_line(r#"pub struct RawServoImportRule(RawServoImportRuleVoid);"#) + .raw_line(r#"pub type RawServoAnimationValueStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowed<'a> = &'a RawServoAnimationValue;"#) + .raw_line(r#"pub type RawServoAnimationValueBorrowedOrNull<'a> = Option<&'a RawServoAnimationValue>;"#) + .raw_line(r#"pub type RawServoAnimationValueMapStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;"#) + .raw_line(r#"pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;"#) + .raw_line(r#"pub type RawServoMediaListStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaListBorrowed<'a> = &'a RawServoMediaList;"#) + .raw_line(r#"pub type RawServoMediaListBorrowedOrNull<'a> = Option<&'a RawServoMediaList>;"#) + .raw_line(r#"enum RawServoMediaListVoid { }"#) + .raw_line(r#"pub struct RawServoMediaList(RawServoMediaListVoid);"#) + .raw_line(r#"pub type RawServoMediaRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowed<'a> = &'a RawServoMediaRule;"#) + .raw_line(r#"pub type RawServoMediaRuleBorrowedOrNull<'a> = Option<&'a RawServoMediaRule>;"#) + .raw_line(r#"enum RawServoMediaRuleVoid { }"#) + .raw_line(r#"pub struct RawServoMediaRule(RawServoMediaRuleVoid);"#) + .raw_line(r#"pub type RawServoNamespaceRuleStrong = ::gecko_bindings::sugar::ownership::Strong;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowed<'a> = &'a RawServoNamespaceRule;"#) + .raw_line(r#"pub type RawServoNamespaceRuleBorrowedOrNull<'a> = Option<&'a RawServoNamespaceRule>;"#) + .raw_line(r#"enum RawServoNamespaceRuleVoid { }"#) + .raw_line(r#"pub struct RawServoNamespaceRule(RawServoNamespaceRuleVoid);"#) + .raw_line(r#"pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;"#) + .raw_line(r#"pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;"#) + .raw_line(r#"enum RawServoStyleSetVoid { }"#) + .raw_line(r#"pub struct RawServoStyleSet(RawServoStyleSetVoid);"#) + .raw_line(r#"pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;"#) + .raw_line(r#"pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;"#) + .raw_line(r#"enum StyleChildrenIteratorVoid { }"#) + .raw_line(r#"pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);"#) + .raw_line(r#"pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned;"#) + .raw_line(r#"pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;"#) + .raw_line(r#"pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;"#) + .raw_line(r#"pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;"#) + .raw_line(r#"pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;"#) + .raw_line(r#"pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;"#) + .raw_line(r#"pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;"#) + .raw_line(r#"pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;"#) + .raw_line(r#"pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;"#) + .raw_line(r#"pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;"#) + .raw_line(r#"pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;"#) + .raw_line(r#"pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;"#) + .raw_line(r#"pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;"#) + .raw_line(r#"pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;"#) + .raw_line(r#"pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;"#) + .raw_line(r#"pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;"#) + .raw_line(r#"pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;"#) + .raw_line(r#"pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;"#) + .raw_line(r#"pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;"#) + .clang_arg("-x") + .clang_arg("c++") + .clang_arg("-std=c++14") + .clang_arg("-DTRACING=1") + .clang_arg("-DIMPL_LIBXUL") + .clang_arg("-DMOZ_STYLO_BINDINGS=1") + .clang_arg("-DMOZILLA_INTERNAL_API") + .clang_arg("-DRUST_BINDGEN") + .clang_arg("-DMOZ_STYLO") + .clang_arg("-DOS_POSIX=1") + .clang_arg("-DOS_LINUX=1") + .generate() + .expect("Should generate stylo bindings"); + + let now = Instant::now(); + + println!(""); + println!(""); + println!("Generated Stylo bindings in: {:?}", + now.duration_since(then)); + println!(""); + println!(""); + + // panic!("Uncomment this line to get timing logs"); +} diff --git a/tests/test-one.sh b/tests/test-one.sh index d1950eb904..cbb89eafb4 100755 --- a/tests/test-one.sh +++ b/tests/test-one.sh @@ -18,16 +18,19 @@ export RUST_BACKTRACE=1 # Grab the first match TEST=$(find ./tests/headers -type f -iname "*$1*" | head -n 1) -BINDINGS=$(mktemp -t bindings_XXXXXX.rs) -TEST_BINDINGS_BINARY=$(mktemp -t bindings.XXXXX) +BINDINGS=$(mktemp -t bindings.rs.XXXXXX) +TEST_BINDINGS_BINARY=$(mktemp -t bindings.XXXXXX) -./target/debug/bindgen \ - "$TEST" \ +FLAGS="$(grep "// bindgen-flags: " "$TEST")" +FLAGS="${FLAGS/\/\/ bindgen\-flags:/}" + +eval ./target/debug/bindgen \ + "\"$TEST\"" \ --emit-ir \ --emit-ir-graphviz ir.dot \ --emit-clang-ast \ - -o "$BINDINGS" \ - -- -std=c++14 + -o "\"$BINDINGS\"" \ + $FLAGS dot -Tpng ir.dot -o ir.png @@ -38,7 +41,7 @@ echo "=== Generated bindings ==================================================" cat "$BINDINGS" echo "=== Building bindings ===================================================" -rustc --test -o "$TEST_BINDINGS_BINARY" "$BINDINGS" +rustc --test -o "$TEST_BINDINGS_BINARY" "$BINDINGS" --crate-name bindgen_test_one echo "=== Testing bindings ====================================================" "$TEST_BINDINGS_BINARY" diff --git a/tests/tests.rs b/tests/tests.rs index bb965bd7ba..c7e03cb567 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -160,3 +160,29 @@ extern \"C\" { } "); } + +#[test] +fn test_multiple_header_calls_in_builder() { + let actual = builder() + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h")) + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/enum.h")) + .generate() + .unwrap() + .to_string(); + + let expected = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs")); + + if actual != expected { + println!("Generated bindings differ from expected!"); + + for diff in diff::lines(&actual, &expected) { + match diff { + diff::Result::Left(l) => println!("-{}", l), + diff::Result::Both(l, _) => println!(" {}", l), + diff::Result::Right(r) => println!("+{}", r), + } + } + + panic!(); + } +}