diff --git a/bindgen-tests/tests/expectations/tests/allowlist-file.rs b/bindgen-tests/tests/expectations/tests/allowlist-file.rs index cb2aa01c59..e70862cd41 100644 --- a/bindgen-tests/tests/expectations/tests/allowlist-file.rs +++ b/bindgen-tests/tests/expectations/tests/allowlist-file.rs @@ -1,5 +1,4 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub const SOME_DEFUN: u32 = 123; extern "C" { #[link_name = "\u{1}_Z12SomeFunctionv"] pub fn SomeFunction(); @@ -7,6 +6,7 @@ extern "C" { extern "C" { pub static mut someVar: ::std::os::raw::c_int; } +pub const SOME_DEFUN: u32 = 123; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct someClass { diff --git a/bindgen-tests/tests/expectations/tests/allowlist_item.rs b/bindgen-tests/tests/expectations/tests/allowlist_item.rs index f816f5170b..5b2a701860 100644 --- a/bindgen-tests/tests/expectations/tests/allowlist_item.rs +++ b/bindgen-tests/tests/expectations/tests/allowlist_item.rs @@ -1,5 +1,4 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub const FooDefault: u32 = 0; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Foo { @@ -13,3 +12,4 @@ const _: () = { extern "C" { pub fn FooNew(value: ::std::os::raw::c_int) -> Foo; } +pub const FooDefault: u32 = 0; diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs index 93fcc92b48..4fecd5969d 100644 --- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs +++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs @@ -84,8 +84,6 @@ where } } pub const JSVAL_TAG_SHIFT: u32 = 47; -pub const JSVAL_PAYLOAD_MASK: u64 = 140737488355327; -pub const JSVAL_TAG_MASK: i64 = -140737488355328; #[repr(u8)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSValueType { @@ -127,6 +125,8 @@ pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_NULL = 18445477436314353664, JSVAL_SHIFTED_TAG_OBJECT = 18445618173802708992, } +pub const JSVAL_PAYLOAD_MASK: u64 = 140737488355327; +pub const JSVAL_TAG_MASK: i64 = -140737488355328; #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSWhyMagic { diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs index 7ae53bc40f..c61b3f940f 100644 --- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs +++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs @@ -127,8 +127,6 @@ impl ::std::cmp::PartialEq for __BindgenUnionField { } impl ::std::cmp::Eq for __BindgenUnionField {} pub const JSVAL_TAG_SHIFT: u32 = 47; -pub const JSVAL_PAYLOAD_MASK: u64 = 140737488355327; -pub const JSVAL_TAG_MASK: i64 = -140737488355328; #[repr(u8)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSValueType { @@ -170,6 +168,8 @@ pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_NULL = 18445477436314353664, JSVAL_SHIFTED_TAG_OBJECT = 18445618173802708992, } +pub const JSVAL_PAYLOAD_MASK: u64 = 140737488355327; +pub const JSVAL_TAG_MASK: i64 = -140737488355328; #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSWhyMagic { diff --git a/bindgen-tests/tests/expectations/tests/layout_arp.rs b/bindgen-tests/tests/expectations/tests/layout_arp.rs index c48fd0e24e..7ae5585e02 100644 --- a/bindgen-tests/tests/expectations/tests/layout_arp.rs +++ b/bindgen-tests/tests/expectations/tests/layout_arp.rs @@ -1,12 +1,5 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] pub const ETHER_ADDR_LEN: u32 = 6; -pub const ARP_HRD_ETHER: u32 = 1; -pub const ARP_OP_REQUEST: u32 = 1; -pub const ARP_OP_REPLY: u32 = 2; -pub const ARP_OP_REVREQUEST: u32 = 3; -pub const ARP_OP_REVREPLY: u32 = 4; -pub const ARP_OP_INVREQUEST: u32 = 8; -pub const ARP_OP_INVREPLY: u32 = 9; /** Ethernet address: A universally administered address is uniquely assigned to a device by its manufacturer. The first three octets (in transmission order) contain the @@ -91,3 +84,10 @@ const _: () = { "Offset of field: arp_hdr::arp_data", ][::std::mem::offset_of!(arp_hdr, arp_data) - 8usize]; }; +pub const ARP_HRD_ETHER: u32 = 1; +pub const ARP_OP_REQUEST: u32 = 1; +pub const ARP_OP_REPLY: u32 = 2; +pub const ARP_OP_REVREQUEST: u32 = 3; +pub const ARP_OP_REVREPLY: u32 = 4; +pub const ARP_OP_INVREQUEST: u32 = 8; +pub const ARP_OP_INVREPLY: u32 = 9; diff --git a/bindgen-tests/tests/expectations/tests/layout_array.rs b/bindgen-tests/tests/expectations/tests/layout_array.rs index b910159beb..140a55750b 100644 --- a/bindgen-tests/tests/expectations/tests/layout_array.rs +++ b/bindgen-tests/tests/expectations/tests/layout_array.rs @@ -1,13 +1,6 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] pub const RTE_CACHE_LINE_SIZE: u32 = 64; pub const RTE_MEMPOOL_OPS_NAMESIZE: u32 = 32; -pub const RTE_MEMPOOL_MAX_OPS_IDX: u32 = 16; -pub const RTE_HEAP_NUM_FREELISTS: u32 = 13; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct rte_mempool { - _unused: [u8; 0], -} /** Prototype for implementation specific data provisioning function. The function should provide the implementation specific memory for @@ -19,6 +12,11 @@ pub struct rte_mempool { pub type rte_mempool_alloc_t = ::std::option::Option< unsafe extern "C" fn(mp: *mut rte_mempool) -> ::std::os::raw::c_int, >; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct rte_mempool { + _unused: [u8; 0], +} /// Free the opaque private data pointed to by mp->pool_data pointer. pub type rte_mempool_free_t = ::std::option::Option< unsafe extern "C" fn(mp: *mut rte_mempool), @@ -122,6 +120,7 @@ impl ::std::cmp::PartialEq for rte_mempool_ops { && self.get_count == other.get_count } } +pub const RTE_MEMPOOL_MAX_OPS_IDX: u32 = 16; /// The rte_spinlock_t type. #[repr(C)] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] @@ -207,6 +206,7 @@ impl Default for rte_mempool_ops_table { } } } +pub const RTE_HEAP_NUM_FREELISTS: u32 = 13; /// Structure to hold malloc heap #[repr(C)] #[repr(align(64))] diff --git a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs index 9b98bac376..206196b77b 100644 --- a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs +++ b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs @@ -90,31 +90,6 @@ pub const ETH_VMDQ_MAX_VLAN_FILTERS: u32 = 64; pub const ETH_DCB_NUM_USER_PRIORITIES: u32 = 8; pub const ETH_VMDQ_DCB_NUM_QUEUES: u32 = 128; pub const ETH_DCB_NUM_QUEUES: u32 = 128; -pub const RTE_ETH_FDIR_MAX_FLEXLEN: u32 = 16; -pub const RTE_ETH_INSET_SIZE_MAX: u32 = 128; -pub const RTE_ETH_FLOW_UNKNOWN: u32 = 0; -pub const RTE_ETH_FLOW_RAW: u32 = 1; -pub const RTE_ETH_FLOW_IPV4: u32 = 2; -pub const RTE_ETH_FLOW_FRAG_IPV4: u32 = 3; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_TCP: u32 = 4; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_UDP: u32 = 5; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: u32 = 6; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: u32 = 7; -pub const RTE_ETH_FLOW_IPV6: u32 = 8; -pub const RTE_ETH_FLOW_FRAG_IPV6: u32 = 9; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_TCP: u32 = 10; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_UDP: u32 = 11; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: u32 = 12; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: u32 = 13; -pub const RTE_ETH_FLOW_L2_PAYLOAD: u32 = 14; -pub const RTE_ETH_FLOW_IPV6_EX: u32 = 15; -pub const RTE_ETH_FLOW_IPV6_TCP_EX: u32 = 16; -pub const RTE_ETH_FLOW_IPV6_UDP_EX: u32 = 17; -pub const RTE_ETH_FLOW_PORT: u32 = 18; -pub const RTE_ETH_FLOW_VXLAN: u32 = 19; -pub const RTE_ETH_FLOW_GENEVE: u32 = 20; -pub const RTE_ETH_FLOW_NVGRE: u32 = 21; -pub const RTE_ETH_FLOW_MAX: u32 = 22; #[repr(u32)] /** A set of values to identify what method is to be used to route packets to multiple queues.*/ @@ -1250,6 +1225,8 @@ pub enum rte_eth_payload_type { RTE_ETH_L4_PAYLOAD = 4, RTE_ETH_PAYLOAD_MAX = 8, } +pub const RTE_ETH_FDIR_MAX_FLEXLEN: u32 = 16; +pub const RTE_ETH_INSET_SIZE_MAX: u32 = 128; /** A structure used to select bytes extracted from the protocol layers to flexible payload for filter*/ #[repr(C)] @@ -1326,6 +1303,29 @@ fn bindgen_test_layout_rte_eth_fdir_flex_mask() { "Offset of field: rte_eth_fdir_flex_mask::mask", ); } +pub const RTE_ETH_FLOW_UNKNOWN: u32 = 0; +pub const RTE_ETH_FLOW_RAW: u32 = 1; +pub const RTE_ETH_FLOW_IPV4: u32 = 2; +pub const RTE_ETH_FLOW_FRAG_IPV4: u32 = 3; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_TCP: u32 = 4; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_UDP: u32 = 5; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: u32 = 6; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: u32 = 7; +pub const RTE_ETH_FLOW_IPV6: u32 = 8; +pub const RTE_ETH_FLOW_FRAG_IPV6: u32 = 9; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_TCP: u32 = 10; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_UDP: u32 = 11; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: u32 = 12; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: u32 = 13; +pub const RTE_ETH_FLOW_L2_PAYLOAD: u32 = 14; +pub const RTE_ETH_FLOW_IPV6_EX: u32 = 15; +pub const RTE_ETH_FLOW_IPV6_TCP_EX: u32 = 16; +pub const RTE_ETH_FLOW_IPV6_UDP_EX: u32 = 17; +pub const RTE_ETH_FLOW_PORT: u32 = 18; +pub const RTE_ETH_FLOW_VXLAN: u32 = 19; +pub const RTE_ETH_FLOW_GENEVE: u32 = 20; +pub const RTE_ETH_FLOW_NVGRE: u32 = 21; +pub const RTE_ETH_FLOW_MAX: u32 = 22; /** A structure used to define all flexible payload related setting include flex payload and flex mask*/ #[repr(C)] diff --git a/bindgen-tests/tests/expectations/tests/layout_eth_conf_1_0.rs b/bindgen-tests/tests/expectations/tests/layout_eth_conf_1_0.rs index 34688b20b3..20ced62470 100644 --- a/bindgen-tests/tests/expectations/tests/layout_eth_conf_1_0.rs +++ b/bindgen-tests/tests/expectations/tests/layout_eth_conf_1_0.rs @@ -133,31 +133,6 @@ pub const ETH_VMDQ_MAX_VLAN_FILTERS: u32 = 64; pub const ETH_DCB_NUM_USER_PRIORITIES: u32 = 8; pub const ETH_VMDQ_DCB_NUM_QUEUES: u32 = 128; pub const ETH_DCB_NUM_QUEUES: u32 = 128; -pub const RTE_ETH_FDIR_MAX_FLEXLEN: u32 = 16; -pub const RTE_ETH_INSET_SIZE_MAX: u32 = 128; -pub const RTE_ETH_FLOW_UNKNOWN: u32 = 0; -pub const RTE_ETH_FLOW_RAW: u32 = 1; -pub const RTE_ETH_FLOW_IPV4: u32 = 2; -pub const RTE_ETH_FLOW_FRAG_IPV4: u32 = 3; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_TCP: u32 = 4; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_UDP: u32 = 5; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: u32 = 6; -pub const RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: u32 = 7; -pub const RTE_ETH_FLOW_IPV6: u32 = 8; -pub const RTE_ETH_FLOW_FRAG_IPV6: u32 = 9; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_TCP: u32 = 10; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_UDP: u32 = 11; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: u32 = 12; -pub const RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: u32 = 13; -pub const RTE_ETH_FLOW_L2_PAYLOAD: u32 = 14; -pub const RTE_ETH_FLOW_IPV6_EX: u32 = 15; -pub const RTE_ETH_FLOW_IPV6_TCP_EX: u32 = 16; -pub const RTE_ETH_FLOW_IPV6_UDP_EX: u32 = 17; -pub const RTE_ETH_FLOW_PORT: u32 = 18; -pub const RTE_ETH_FLOW_VXLAN: u32 = 19; -pub const RTE_ETH_FLOW_GENEVE: u32 = 20; -pub const RTE_ETH_FLOW_NVGRE: u32 = 21; -pub const RTE_ETH_FLOW_MAX: u32 = 22; #[repr(u32)] /** A set of values to identify what method is to be used to route packets to multiple queues.*/ @@ -1363,6 +1338,8 @@ pub enum rte_eth_payload_type { RTE_ETH_L4_PAYLOAD = 4, RTE_ETH_PAYLOAD_MAX = 8, } +pub const RTE_ETH_FDIR_MAX_FLEXLEN: u32 = 16; +pub const RTE_ETH_INSET_SIZE_MAX: u32 = 128; /** A structure used to select bytes extracted from the protocol layers to flexible payload for filter*/ #[repr(C)] @@ -1449,6 +1426,29 @@ impl Clone for rte_eth_fdir_flex_mask { *self } } +pub const RTE_ETH_FLOW_UNKNOWN: u32 = 0; +pub const RTE_ETH_FLOW_RAW: u32 = 1; +pub const RTE_ETH_FLOW_IPV4: u32 = 2; +pub const RTE_ETH_FLOW_FRAG_IPV4: u32 = 3; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_TCP: u32 = 4; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_UDP: u32 = 5; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: u32 = 6; +pub const RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: u32 = 7; +pub const RTE_ETH_FLOW_IPV6: u32 = 8; +pub const RTE_ETH_FLOW_FRAG_IPV6: u32 = 9; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_TCP: u32 = 10; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_UDP: u32 = 11; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: u32 = 12; +pub const RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: u32 = 13; +pub const RTE_ETH_FLOW_L2_PAYLOAD: u32 = 14; +pub const RTE_ETH_FLOW_IPV6_EX: u32 = 15; +pub const RTE_ETH_FLOW_IPV6_TCP_EX: u32 = 16; +pub const RTE_ETH_FLOW_IPV6_UDP_EX: u32 = 17; +pub const RTE_ETH_FLOW_PORT: u32 = 18; +pub const RTE_ETH_FLOW_VXLAN: u32 = 19; +pub const RTE_ETH_FLOW_GENEVE: u32 = 20; +pub const RTE_ETH_FLOW_NVGRE: u32 = 21; +pub const RTE_ETH_FLOW_MAX: u32 = 22; /** A structure used to define all flexible payload related setting include flex payload and flex mask*/ #[repr(C)] diff --git a/bindgen-tests/tests/expectations/tests/namespace.rs b/bindgen-tests/tests/expectations/tests/namespace.rs index 93e201d329..28607dee32 100644 --- a/bindgen-tests/tests/expectations/tests/namespace.rs +++ b/bindgen-tests/tests/expectations/tests/namespace.rs @@ -17,7 +17,7 @@ pub mod root { pub fn in_whatever(); } } - pub mod _bindgen_mod_id_17 { + pub mod _bindgen_mod_id_13 { #[allow(unused_imports)] use self::super::super::root; #[repr(C)] @@ -35,7 +35,7 @@ pub mod root { #[derive(Debug)] pub struct C { pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - pub _base: root::_bindgen_mod_id_17::A, + pub _base: root::_bindgen_mod_id_13::A, pub m_c: T, pub m_c_ptr: *mut T, pub m_c_arr: [T; 10usize], diff --git a/bindgen-tests/tests/expectations/tests/source-order-nested.rs b/bindgen-tests/tests/expectations/tests/source-order-nested.rs new file mode 100644 index 0000000000..59eadaa48f --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/source-order-nested.rs @@ -0,0 +1,20 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const THIS_SHOULD_BE_FIRST: ::std::os::raw::c_int = 1; +extern "C" { + pub fn THIS_SHOULD_BE_SECOND(); +} +pub type THIS_SHOULD_BE_THIRD = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct THIS_SHOULD_BE_FOURTH {} +const _: () = { + [ + "Size of THIS_SHOULD_BE_FOURTH", + ][::std::mem::size_of::() - 0usize]; + [ + "Alignment of THIS_SHOULD_BE_FOURTH", + ][::std::mem::align_of::() - 1usize]; +}; +extern "C" { + pub static mut THIS_SHOULD_BE_FIFTH: ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/expectations/tests/source-order-recursive.rs b/bindgen-tests/tests/expectations/tests/source-order-recursive.rs new file mode 100644 index 0000000000..ab92066c97 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/source-order-recursive.rs @@ -0,0 +1,28 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct foo {} +const _: () = { + ["Size of foo"][::std::mem::size_of::() - 0usize]; + ["Alignment of foo"][::std::mem::align_of::() - 1usize]; +}; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct bar { + pub field: foo, +} +const _: () = { + ["Size of bar"][::std::mem::size_of::() - 0usize]; + ["Alignment of bar"][::std::mem::align_of::() - 1usize]; + ["Offset of field: bar::field"][::std::mem::offset_of!(bar, field) - 0usize]; +}; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct baz { + pub field: bar, +} +const _: () = { + ["Size of baz"][::std::mem::size_of::() - 0usize]; + ["Alignment of baz"][::std::mem::align_of::() - 1usize]; + ["Offset of field: baz::field"][::std::mem::offset_of!(baz, field) - 0usize]; +}; diff --git a/bindgen-tests/tests/expectations/tests/source-order-siblings.rs b/bindgen-tests/tests/expectations/tests/source-order-siblings.rs new file mode 100644 index 0000000000..02585bed4b --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/source-order-siblings.rs @@ -0,0 +1,14 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const ROOT: &[u8; 5] = b"root\0"; +pub const A: ::std::os::raw::c_char = 97; +extern "C" { + pub fn AA(); +} +pub const B: u8 = 98u8; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BB {} +const _: () = { + ["Size of BB"][::std::mem::size_of::() - 0usize]; + ["Alignment of BB"][::std::mem::align_of::() - 1usize]; +}; diff --git a/bindgen-tests/tests/expectations/tests/template_instantiation_with_fn_local_type.rs b/bindgen-tests/tests/expectations/tests/template_instantiation_with_fn_local_type.rs index f152f1ae8e..068a970488 100644 --- a/bindgen-tests/tests/expectations/tests/template_instantiation_with_fn_local_type.rs +++ b/bindgen-tests/tests/expectations/tests/template_instantiation_with_fn_local_type.rs @@ -4,10 +4,6 @@ pub struct Foo { pub _address: u8, } -extern "C" { - #[link_name = "\u{1}_Z1fv"] - pub fn f(); -} const _: () = { [ "Size of template specialization: Foo_open0_Bar_close0", @@ -16,6 +12,18 @@ const _: () = { "Align of template specialization: Foo_open0_Bar_close0", ][::std::mem::align_of::() - 1usize]; }; +const _: () = { + [ + "Size of template specialization: Foo_open0_Boo_close0", + ][::std::mem::size_of::() - 1usize]; + [ + "Align of template specialization: Foo_open0_Boo_close0", + ][::std::mem::align_of::() - 1usize]; +}; +extern "C" { + #[link_name = "\u{1}_Z1fv"] + pub fn f(); +} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Baz { @@ -25,14 +33,6 @@ const _: () = { ["Size of Baz"][::std::mem::size_of::() - 1usize]; ["Alignment of Baz"][::std::mem::align_of::() - 1usize]; }; -const _: () = { - [ - "Size of template specialization: Foo_open0_Boo_close0", - ][::std::mem::size_of::() - 1usize]; - [ - "Align of template specialization: Foo_open0_Boo_close0", - ][::std::mem::align_of::() - 1usize]; -}; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Bar { diff --git a/bindgen-tests/tests/headers/issue-2556.h b/bindgen-tests/tests/headers/issue-2556.h index bbb1b874ec..88a559e191 100644 --- a/bindgen-tests/tests/headers/issue-2556.h +++ b/bindgen-tests/tests/headers/issue-2556.h @@ -1,4 +1,4 @@ -// bindgen-flags: --enable-cxx-namespaces -- -x c++ -Itests/headers -include tests/headers/issue-2556/nsStyleStruct.h -include tests/headers/issue-2556/LayoutConstants.h +// bindgen-flags: --enable-cxx-namespaces -- -x c++ -std=c++11 -Itests/headers -include tests/headers/issue-2556/nsStyleStruct.h -include tests/headers/issue-2556/LayoutConstants.h #include "issue-2556/nsSize.h" #include "issue-2556/nsStyleStruct.h" diff --git a/bindgen-tests/tests/headers/source-order-nested.h b/bindgen-tests/tests/headers/source-order-nested.h new file mode 100644 index 0000000000..2a51cf971c --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-nested.h @@ -0,0 +1,7 @@ +// bindgen-flags: -- -Itests/headers/source-order-nested + +const int THIS_SHOULD_BE_FIRST = 1; + +#include "source-order-nested-2.h" + +extern int THIS_SHOULD_BE_FIFTH; diff --git a/bindgen-tests/tests/headers/source-order-nested/source-order-nested-2.h b/bindgen-tests/tests/headers/source-order-nested/source-order-nested-2.h new file mode 100644 index 0000000000..a9db8fd54f --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-nested/source-order-nested-2.h @@ -0,0 +1,7 @@ +#pragma once + +void THIS_SHOULD_BE_SECOND(); + +#include "source-order-nested-3.h" + +struct THIS_SHOULD_BE_FOURTH {}; diff --git a/bindgen-tests/tests/headers/source-order-nested/source-order-nested-3.h b/bindgen-tests/tests/headers/source-order-nested/source-order-nested-3.h new file mode 100644 index 0000000000..67b9a838cf --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-nested/source-order-nested-3.h @@ -0,0 +1,3 @@ +#pragma once + +typedef int THIS_SHOULD_BE_THIRD; diff --git a/bindgen-tests/tests/headers/source-order-recursive.h b/bindgen-tests/tests/headers/source-order-recursive.h new file mode 100644 index 0000000000..6d589a7f7c --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-recursive.h @@ -0,0 +1,14 @@ +// bindgen-flags: -- -Itests/headers -Itests/headers/source-order-recursive + +#ifndef A_H +#define A_H + +struct foo {}; + +#include "source-order-recursive-2.h" + +struct baz { + struct bar field; +}; + +#endif diff --git a/bindgen-tests/tests/headers/source-order-recursive/source-order-recursive-2.h b/bindgen-tests/tests/headers/source-order-recursive/source-order-recursive-2.h new file mode 100644 index 0000000000..01ff1890b1 --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-recursive/source-order-recursive-2.h @@ -0,0 +1,5 @@ +#include "source-order-recursive.h" + +struct bar { + struct foo field; +}; diff --git a/bindgen-tests/tests/headers/source-order-siblings.h b/bindgen-tests/tests/headers/source-order-siblings.h new file mode 100644 index 0000000000..9533152829 --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-siblings.h @@ -0,0 +1,6 @@ +// bindgen-flags: -- -Itests/headers/source-order-siblings + +const char* ROOT = "root"; + +#include "a.h" +#include "b.h" diff --git a/bindgen-tests/tests/headers/source-order-siblings/a.h b/bindgen-tests/tests/headers/source-order-siblings/a.h new file mode 100644 index 0000000000..7821b612df --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-siblings/a.h @@ -0,0 +1,5 @@ +#pragma once + +const char A = 'a'; + +#include "aa.h" diff --git a/bindgen-tests/tests/headers/source-order-siblings/aa.h b/bindgen-tests/tests/headers/source-order-siblings/aa.h new file mode 100644 index 0000000000..9fa550902f --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-siblings/aa.h @@ -0,0 +1,3 @@ +#pragma once + +void AA(); diff --git a/bindgen-tests/tests/headers/source-order-siblings/b.h b/bindgen-tests/tests/headers/source-order-siblings/b.h new file mode 100644 index 0000000000..fc6740afaa --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-siblings/b.h @@ -0,0 +1,5 @@ +#pragma once + +#define B 'b' + +#include "bb.h" diff --git a/bindgen-tests/tests/headers/source-order-siblings/bb.h b/bindgen-tests/tests/headers/source-order-siblings/bb.h new file mode 100644 index 0000000000..81d03e82f7 --- /dev/null +++ b/bindgen-tests/tests/headers/source-order-siblings/bb.h @@ -0,0 +1,3 @@ +#pragma once + +struct BB {}; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 14988e463f..6bf084bc75 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -535,9 +535,9 @@ fn test_mixed_header_and_header_contents() { env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h" )) - .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h")) .header_contents("test.h", "int bar(const char* a);") .header_contents("test2.h", "float bar2(const char* b);") + .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h")) .clang_arg("--target=x86_64-unknown-linux") .generate() .unwrap() diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 26c02acec9..197744f179 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -4,16 +4,20 @@ #![allow(non_upper_case_globals, dead_code)] #![deny(clippy::missing_docs_in_private_items)] -use crate::ir::context::BindgenContext; +use crate::ir::context::{BindgenContext, IncludeLocation}; use clang_sys::*; +use std::borrow::Cow; use std::cmp; - +use std::convert::TryInto; +use std::env::current_dir; use std::ffi::{CStr, CString}; use std::fmt; use std::fs::OpenOptions; use std::hash::Hash; use std::hash::Hasher; use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong}; +use std::path::Path; +use std::path::PathBuf; use std::sync::OnceLock; use std::{mem, ptr, slice}; @@ -137,8 +141,7 @@ impl Cursor { /// Returns whether the cursor refers to a built-in definition. pub(crate) fn is_builtin(&self) -> bool { - let (file, _, _, _) = self.location().location(); - file.name().is_none() + matches!(self.location(), SourceLocation::Builtin { .. }) } /// Get the `Cursor` for this cursor's referent's lexical parent. @@ -378,8 +381,31 @@ impl Cursor { /// Get the source location for the referent. pub(crate) fn location(&self) -> SourceLocation { unsafe { - SourceLocation { - x: clang_getCursorLocation(self.x), + let location = clang_getCursorLocation(self.x); + + let mut file = mem::zeroed(); + let mut line = 0; + let mut column = 0; + let mut offset = 0; + clang_getSpellingLocation( + location, + &mut file, + &mut line, + &mut column, + &mut offset, + ); + + if file.is_null() { + SourceLocation::Builtin { + offset: offset.try_into().unwrap(), + } + } else { + SourceLocation::File { + file: SourceFile::from_raw(file), + line: line.try_into().unwrap(), + column: column.try_into().unwrap(), + offset: offset.try_into().unwrap(), + } } } } @@ -510,27 +536,11 @@ impl Cursor { ) where Visitor: FnMut(&mut BindgenContext, Cursor), { - // FIXME(#2556): The current source order stuff doesn't account well for different levels - // of includes, or includes that show up at the same byte offset because they are passed in - // via CLI. - const SOURCE_ORDER_ENABLED: bool = false; - if !SOURCE_ORDER_ENABLED { - return self.visit(|c| { - visitor(ctx, c); - CXChildVisit_Continue - }); - } - let mut children = self.collect_children(); for child in &children { if child.kind() == CXCursor_InclusionDirective { - if let Some(included_file) = child.get_included_file_name() { - let location = child.location(); - let (source_file, _, _, offset) = location.location(); - - if let Some(source_file) = source_file.name() { - ctx.add_include(source_file, included_file, offset); - } + if let Some(included_file) = child.get_included_file() { + ctx.add_include(included_file, child.location()); } } } @@ -541,53 +551,16 @@ impl Cursor { } } - /// Compare source order of two cursors, considering `#include` directives. - /// - /// Built-in items provided by the compiler (which don't have a source file), - /// are sorted first. Remaining files are sorted by their position in the source file. - /// If the items' source files differ, they are sorted by the position of the first - /// `#include` for their source file. If no source files are included, `None` is returned. + /// Compare two cursors according how they appear in source files. fn cmp_by_source_order( &self, other: &Self, ctx: &BindgenContext, ) -> cmp::Ordering { - let (file, _, _, offset) = self.location().location(); - let (other_file, _, _, other_offset) = other.location().location(); - - let (file, other_file) = match (file.name(), other_file.name()) { - (Some(file), Some(other_file)) => (file, other_file), - // Built-in definitions should come first. - (Some(_), None) => return cmp::Ordering::Greater, - (None, Some(_)) => return cmp::Ordering::Less, - (None, None) => return cmp::Ordering::Equal, - }; + let location = self.location(); + let other_location = other.location(); - if file == other_file { - // Both items are in the same source file, compare by byte offset. - return offset.cmp(&other_offset); - } - - let include_location = ctx.included_file_location(&file); - let other_include_location = ctx.included_file_location(&other_file); - match (include_location, other_include_location) { - (Some((file2, offset2)), _) if file2 == other_file => { - offset2.cmp(&other_offset) - } - (Some(_), None) => cmp::Ordering::Greater, - (_, Some((other_file2, other_offset2))) if file == other_file2 => { - offset.cmp(&other_offset2) - } - (None, Some(_)) => cmp::Ordering::Less, - (Some((file2, offset2)), Some((other_file2, other_offset2))) => { - if file2 == other_file2 { - offset2.cmp(&other_offset2) - } else { - cmp::Ordering::Equal - } - } - (None, None) => cmp::Ordering::Equal, - } + location.cmp_by_source_order(&other_location, ctx) } /// Collect all of this cursor's children into a vec and return them. @@ -960,14 +933,12 @@ impl Cursor { /// Obtain the real path name of a cursor of InclusionDirective kind. /// /// Returns None if the cursor does not include a file, otherwise the file's full name - pub(crate) fn get_included_file_name(&self) -> Option { - let file = unsafe { clang_sys::clang_getIncludedFile(self.x) }; + pub(crate) fn get_included_file(&self) -> Option { + let file = unsafe { clang_getIncludedFile(self.x) }; if file.is_null() { None } else { - Some(unsafe { - cxstring_into_string(clang_sys::clang_getFileName(file)) - }) + Some(unsafe { SourceFile::from_raw(file) }) } } } @@ -1595,36 +1566,121 @@ impl ExactSizeIterator for TypeTemplateArgIterator { } } -/// A `SourceLocation` is a file, line, column, and byte offset location for -/// some source text. -pub(crate) struct SourceLocation { - x: CXSourceLocation, +/// A location of some source code. +#[derive(Clone)] +pub(crate) enum SourceLocation { + /// Location of a built-in. + Builtin { + /// Offset. + offset: usize, + }, + /// Location in a source file. + File { + /// The source file. + file: SourceFile, + /// Line in the source file. + line: usize, + /// Column in the source file. + column: usize, + /// Offset in the source file. + offset: usize, + }, } impl SourceLocation { - /// Get the (file, line, column, byte offset) tuple for this source - /// location. - pub(crate) 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_getFileLocation( - self.x, &mut file, &mut line, &mut col, &mut off, - ); - (File { x: file }, line as usize, col as usize, off as usize) + /// Locations of built-in items provided by the compiler (which don't have a source file), + /// are sorted first. Remaining locations are sorted by their position in the source file. + /// If the locations' source files differ, they are sorted by the position of where the + /// source files are first transitively included, see `IncludeLocation::cmp_by_source_order`. + pub fn cmp_by_source_order( + &self, + other: &Self, + ctx: &BindgenContext, + ) -> cmp::Ordering { + match (self, other) { + ( + SourceLocation::Builtin { offset }, + SourceLocation::Builtin { + offset: other_offset, + }, + ) => offset.cmp(other_offset), + // Built-ins come first. + (SourceLocation::Builtin { .. }, _) => cmp::Ordering::Less, + (_, SourceLocation::Builtin { .. }) => { + other.cmp_by_source_order(self, ctx).reverse() + } + ( + SourceLocation::File { file, offset, .. }, + SourceLocation::File { + file: other_file, + offset: other_offset, + .. + }, + ) => { + let file_path = file.path(); + let other_file_path = other_file.path(); + + if file_path == other_file_path { + return offset.cmp(other_offset); + } + + // If `file` is transitively included via `ancestor_file`, + // find the offset of the include directive in `ancestor_file`. + let offset_in_ancestor = + |file_path: &Path, ancestor_file_path: &Path| { + let mut file_path = Cow::Borrowed(file_path); + while file_path != ancestor_file_path { + let include_location = + ctx.include_location(file_path); + file_path = if let IncludeLocation::File { + file, + offset, + .. + } = include_location + { + let file_path = Cow::Owned(file.path()); + + if file_path == ancestor_file_path { + return Some(offset); + } + + file_path + } else { + break; + } + } + + None + }; + + if let Some(offset) = + offset_in_ancestor(&file_path, &other_file_path) + { + return offset.cmp(other_offset); + } + + if let Some(other_offset) = + offset_in_ancestor(&other_file_path, &file_path) + { + return offset.cmp(other_offset); + } + + // If the source files are siblings, compare their include locations. + let parent = ctx.include_location(file_path); + let other_parent = ctx.include_location(&other_file_path); + parent.cmp_by_source_order(other_parent, ctx) + } } } } 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) + match self { + Self::Builtin { .. } => "built-in".fmt(f), + Self::File { + file, line, column, .. + } => write!(f, "{}:{}:{}", file.path().display(), line, column), } } } @@ -1735,31 +1791,62 @@ impl Iterator for CommentAttributesIterator { } /// A source file. -pub(crate) struct File { - x: CXFile, +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct SourceFile { + name: Box, } -impl File { - /// Get the name of this source file. - pub(crate) fn name(&self) -> Option { - if self.x.is_null() { - return None; +impl SourceFile { + /// Creates a new `SourceFile` from a file name. + #[inline] + pub fn new>(name: P) -> Self { + Self { + name: name.as_ref().to_owned().into_boxed_str(), + } + } + + /// Creates a new `SourceFile` from a raw pointer. + /// + /// # Safety + /// + /// `file` must point to a valid `CXFile`. + pub unsafe fn from_raw(file: CXFile) -> Self { + let name = unsafe { cxstring_into_string(clang_getFileName(file)) }; + + Self::new(name) + } + + #[inline] + pub fn name(&self) -> &str { + &self.name + } + + /// Get the path of this source file. + pub fn path(&self) -> PathBuf { + let path = Path::new(self.name()); + if path.is_relative() { + current_dir() + .expect("Cannot retrieve current directory") + .join(path) + } else { + path.to_owned() } - Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) } } -fn cxstring_to_string_leaky(s: CXString) -> String { +unsafe fn cxstring_to_string_leaky(s: CXString) -> String { if s.data.is_null() { - return "".to_owned(); + Cow::Borrowed("") + } else { + let c_str = CStr::from_ptr(clang_getCString(s) as *const _); + c_str.to_string_lossy() } - let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) }; - c_str.to_string_lossy().into_owned() + .into_owned() } -fn cxstring_into_string(s: CXString) -> String { +unsafe fn cxstring_into_string(s: CXString) -> String { let ret = cxstring_to_string_leaky(s); - unsafe { clang_disposeString(s) }; + clang_disposeString(s); ret } @@ -1870,6 +1957,15 @@ impl TranslationUnit { } } + /// Get the source file of this. + pub fn file(&self) -> SourceFile { + let name = unsafe { + cxstring_into_string(clang_getTranslationUnitSpelling(self.x)) + }; + + SourceFile::new(name) + } + /// Save a translation unit to the given file. pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> { let file = if let Ok(cstring) = CString::new(file) { diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 0b23e0acc3..c299a0ad2e 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4631,17 +4631,21 @@ fn unsupported_abi_diagnostic( Level::Note, ); - if let Some(loc) = location { - let (file, line, col, _) = loc.location(); - - if let Some(filename) = file.name() { - if let Ok(Some(source)) = get_line(&filename, line) { - let mut slice = Slice::default(); - slice - .with_source(source) - .with_location(filename, line, col); - diag.add_slice(slice); - } + if let Some(crate::clang::SourceLocation::File { + file, + line, + column, + .. + }) = location.cloned() + { + if let Ok(Some(source)) = get_line(file.path(), line) { + let mut slice = Slice::default(); + slice.with_source(source).with_location( + file.name(), + line, + column, + ); + diag.add_slice(slice); } } @@ -4649,10 +4653,11 @@ fn unsupported_abi_diagnostic( } } +#[cfg_attr(not(feature = "experimental"), allow(unused_variables))] fn variadic_fn_diagnostic( fn_name: &str, - _location: Option<&crate::clang::SourceLocation>, - _ctx: &BindgenContext, + location: Option<&crate::clang::SourceLocation>, + ctx: &BindgenContext, ) { warn!( "Cannot generate wrapper for the static variadic function `{}`.", @@ -4660,7 +4665,7 @@ fn variadic_fn_diagnostic( ); #[cfg(feature = "experimental")] - if _ctx.options().emit_diagnostics { + if ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; let mut diag = Diagnostic::default(); @@ -4669,17 +4674,21 @@ fn variadic_fn_diagnostic( .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note) .add_annotation("No code will be generated for this function.", Level::Note); - if let Some(loc) = _location { - let (file, line, col, _) = loc.location(); - - if let Some(filename) = file.name() { - if let Ok(Some(source)) = get_line(&filename, line) { - let mut slice = Slice::default(); - slice - .with_source(source) - .with_location(filename, line, col); - diag.add_slice(slice); - } + if let Some(crate::clang::SourceLocation::File { + file, + line, + column, + .. + }) = location.cloned() + { + if let Ok(Some(source)) = get_line(file.path(), line) { + let mut slice = Slice::default(); + slice.with_source(source).with_location( + file.name(), + line, + column, + ); + diag.add_slice(slice); } } diff --git a/bindgen/deps.rs b/bindgen/deps.rs index be31f92896..6d26b537d2 100644 --- a/bindgen/deps.rs +++ b/bindgen/deps.rs @@ -1,6 +1,8 @@ /// Generating build depfiles from parsed bindings. use std::{collections::BTreeSet, path::PathBuf}; +use crate::clang::SourceFile; + #[derive(Clone, Debug)] pub(crate) struct DepfileSpec { pub output_module: String, @@ -8,17 +10,17 @@ pub(crate) struct DepfileSpec { } impl DepfileSpec { - pub fn write(&self, deps: &BTreeSet>) -> std::io::Result<()> { + pub fn write(&self, deps: &BTreeSet) -> std::io::Result<()> { std::fs::write(&self.depfile_path, self.to_string(deps)) } - fn to_string(&self, deps: &BTreeSet>) -> String { + fn to_string(&self, deps: &BTreeSet) -> String { // Transforms a string by escaping spaces and backslashes. let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ "); let mut buf = format!("{}:", escape(&self.output_module)); for file in deps { - buf = format!("{} {}", buf, escape(file)); + buf = format!("{} {}", buf, escape(file.name())); } buf } @@ -36,13 +38,13 @@ mod tests { }; let deps: BTreeSet<_> = vec![ - r"/absolute/path".into(), - r"C:\win\absolute\path".into(), - r"../relative/path".into(), - r"..\win\relative\path".into(), - r"../path/with spaces/in/it".into(), - r"..\win\path\with spaces\in\it".into(), - r"path\with/mixed\separators".into(), + SourceFile::new(r"/absolute/path"), + SourceFile::new(r"C:\win\absolute\path"), + SourceFile::new(r"../relative/path"), + SourceFile::new(r"..\win\relative\path"), + SourceFile::new(r"../path/with spaces/in/it"), + SourceFile::new(r"..\win\path\with spaces\in\it"), + SourceFile::new(r"path\with/mixed\separators"), ] .into_iter() .collect(); diff --git a/bindgen/diagnostics.rs b/bindgen/diagnostics.rs index f765afe970..df28c0ac3a 100644 --- a/bindgen/diagnostics.rs +++ b/bindgen/diagnostics.rs @@ -2,8 +2,8 @@ //! //! The entry point of this module is the [`Diagnostic`] type. -use std::fmt::Write; use std::io::{self, BufRead, BufReader}; +use std::path::Path; use std::{borrow::Cow, fs::File}; use annotate_snippets::{ @@ -110,7 +110,7 @@ impl<'a> Diagnostic<'a> { slices.push(ExtSlice { source: source.as_ref(), line_start: slice.line.unwrap_or_default(), - origin: slice.filename.as_deref(), + origin: slice.origin.as_deref(), annotations: vec![], fold: false, }) @@ -146,9 +146,9 @@ impl<'a> Diagnostic<'a> { /// A slice of source code. #[derive(Default)] pub(crate) struct Slice<'a> { - source: Option>, - filename: Option, line: Option, + origin: Option, + source: Option>, } impl<'a> Slice<'a> { @@ -164,23 +164,21 @@ impl<'a> Slice<'a> { /// Set the file, line and column. pub(crate) fn with_location( &mut self, - mut name: String, + file_name: &str, line: usize, - col: usize, + column: usize, ) -> &mut Self { - write!(name, ":{}:{}", line, col) - .expect("Writing to a string cannot fail"); - self.filename = Some(name); self.line = Some(line); + self.origin = Some(format!("{file_name}:{line}:{column}")); self } } -pub(crate) fn get_line( - filename: &str, +pub(crate) fn get_line>( + file_path: P, line: usize, ) -> io::Result> { - let file = BufReader::new(File::open(filename)?); + let file = BufReader::new(File::open(file_path.as_ref())?); if let Some(line) = file.lines().nth(line.wrapping_sub(1)) { return line.map(Some); } diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index a1536935b6..3689558ded 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -19,7 +19,7 @@ use super::module::{Module, ModuleKind}; use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; -use crate::clang::{self, ABIKind, Cursor}; +use crate::clang::{self, ABIKind, Cursor, SourceFile, SourceLocation}; use crate::codegen::CodegenError; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; @@ -31,8 +31,8 @@ use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap as StdHashMap}; use std::fs::OpenOptions; use std::io::Write; -use std::mem; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::{cmp, mem}; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] @@ -307,6 +307,108 @@ enum TypeKey { Declaration(Cursor), } +/// Specifies where a header was included from. +#[derive(Debug)] +pub(crate) enum IncludeLocation { + /// Include location of the main header file, i.e. none. + Main, + /// Include location of a header specified as a CLI argument. + Cli { + /// Offset of the include location. + offset: usize, + }, + /// Include location of a header included with an `#include` directive. + File { + /// Source file name of the include location. + file: SourceFile, + /// Line of the include location. + line: usize, + /// Column of the include location. + column: usize, + /// Offset of the include location. + offset: usize, + }, +} + +impl IncludeLocation { + /// Header include locations are sorted in the order they appear in, which means + /// headers provided as command line arguments (`-include`) are sorted first, + /// followed by the main header file, and lastly headers included with `#include` + /// directives. + /// + /// Nested headers are sorted according to where they were transitively included first. + pub fn cmp_by_source_order( + &self, + other: &Self, + ctx: &BindgenContext, + ) -> cmp::Ordering { + match (self, other) { + // If both headers are included via CLI argument, compare their offset. + ( + IncludeLocation::Cli { offset }, + IncludeLocation::Cli { + offset: other_offset, + }, + ) => offset.cmp(other_offset), + // Headers included via CLI arguments come first. + (IncludeLocation::Cli { .. }, IncludeLocation::Main) => { + cmp::Ordering::Less + } + (IncludeLocation::Main, IncludeLocation::Cli { .. }) => { + cmp::Ordering::Greater + } + // If both includes refer to the main header file, they are equal. + (IncludeLocation::Main, IncludeLocation::Main) => { + cmp::Ordering::Equal + } + // If one is included via CLI arguments or the main header file, + // recursively compare with the other's include location. + ( + IncludeLocation::Cli { .. } | IncludeLocation::Main, + IncludeLocation::File { + file: other_file, .. + }, + ) => { + let other_parent = ctx.include_location(other_file.path()); + self.cmp_by_source_order(other_parent, ctx) + } + ( + IncludeLocation::File { .. }, + IncludeLocation::Cli { .. } | IncludeLocation::Main, + ) => other.cmp_by_source_order(self, ctx).reverse(), + // If both include locations are in files, compare them as `SourceLocation`s. + ( + IncludeLocation::File { + file, + line, + column, + offset, + }, + IncludeLocation::File { + file: other_file, + line: other_line, + column: other_column, + offset: other_offset, + }, + ) => SourceLocation::File { + file: file.clone(), + line: *line, + column: *column, + offset: *offset, + } + .cmp_by_source_order( + &SourceLocation::File { + file: other_file.clone(), + line: *other_line, + column: *other_column, + offset: *other_offset, + }, + ctx, + ), + } + } +} + /// A context used during parsing and generation of structs. #[derive(Debug)] pub(crate) struct BindgenContext { @@ -364,10 +466,10 @@ pub(crate) struct BindgenContext { /// /// The key is the included file, the value is a pair of the source file and /// the position of the `#include` directive in the source file. - includes: StdHashMap, + includes: StdHashMap, /// A set of all the included filenames. - deps: BTreeSet>, + deps: BTreeSet, /// The active replacements collected from replaces="xxx" annotations. replacements: HashMap, ItemId>, @@ -572,7 +674,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" let root_module_id = root_module.id().as_module_id_unchecked(); // depfiles need to include the explicitly listed headers too - let deps = options.input_headers.iter().cloned().collect(); + let deps = options.input_headers.iter().map(SourceFile::new).collect(); BindgenContext { items: vec![Some(root_module)], @@ -658,33 +760,65 @@ If you encounter an error missing from this list, please file an issue or a PR!" ) } - /// Add the location of the `#include` directive for the `included_file`. + /// Add the location of where `included_file` is included. pub(crate) fn add_include( &mut self, - source_file: String, - included_file: String, - offset: usize, + included_file: SourceFile, + source_location: SourceLocation, ) { - self.includes - .entry(included_file) - .or_insert((source_file, offset)); + let included_file_path = included_file.path(); + + if self.includes.contains_key(&included_file_path) { + return; + } + + let include_location = { + // Recursively including the main header file doesn't count. + if self.translation_unit.file().path() == included_file_path { + IncludeLocation::Main + } else { + match source_location { + // Include location is a built-in, so it must have been included via CLI arguments. + SourceLocation::Builtin { offset } => { + IncludeLocation::Cli { offset } + } + // Header was included with an `#include` directive. + SourceLocation::File { + file, + line, + column, + offset, + } => IncludeLocation::File { + file, + line, + column, + offset, + }, + } + } + }; + + self.includes.insert(included_file_path, include_location); } - /// Get the location of the first `#include` directive for the `included_file`. - pub(crate) fn included_file_location( + /// Get the location of the first `#include` directive for the `included_file_path`. + pub(crate) fn include_location>( &self, - included_file: &str, - ) -> Option<(String, usize)> { - self.includes.get(included_file).cloned() + included_file_path: P, + ) -> &IncludeLocation { + self.includes.get(included_file_path.as_ref()).unwrap_or( + // Header was not included anywhere, so it must be the main header. + &IncludeLocation::Main, + ) } /// Add an included file. - pub(crate) fn add_dep(&mut self, dep: Box) { + pub(crate) fn add_dep(&mut self, dep: SourceFile) { self.deps.insert(dep); } /// Get any included files. - pub(crate) fn deps(&self) -> &BTreeSet> { + pub(crate) fn deps(&self) -> &BTreeSet { &self.deps } @@ -2482,16 +2616,15 @@ If you encounter an error missing from this list, please file an issue or a PR!" // Items with a source location in an explicitly allowlisted file // are always included. if !self.options().allowlisted_files.is_empty() { - if let Some(location) = item.location() { - let (file, _, _, _) = location.location(); - if let Some(filename) = file.name() { - if self - .options() - .allowlisted_files - .matches(filename) - { - return true; - } + if let Some(SourceLocation::File { file, .. }) = + item.location() + { + if self + .options() + .allowlisted_files + .matches(file.name()) + { + return true; } } } diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs index 8dc7bf84ee..c7c91792ce 100644 --- a/bindgen/ir/item.rs +++ b/bindgen/ir/item.rs @@ -17,7 +17,7 @@ use super::module::Module; use super::template::{AsTemplateParam, TemplateParameters}; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::{Type, TypeKind}; -use crate::clang; +use crate::clang::{self, SourceLocation}; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use std::cell::{Cell, OnceCell}; @@ -640,12 +640,9 @@ impl Item { } if !ctx.options().blocklisted_files.is_empty() { - if let Some(location) = &self.location { - let (file, _, _, _) = location.location(); - if let Some(filename) = file.name() { - if ctx.options().blocklisted_files.matches(filename) { - return true; - } + if let Some(SourceLocation::File { file, .. }) = &self.location { + if ctx.options().blocklisted_files.matches(file.name()) { + return true; } } } @@ -1429,17 +1426,17 @@ impl Item { } CXCursor_InclusionDirective => { - let file = cursor.get_included_file_name(); + let file = cursor.get_included_file(); match file { - None => { - warn!("Inclusion of a nameless file in {:?}", cursor); - } Some(included_file) => { for cb in &ctx.options().parse_callbacks { - cb.include_file(&included_file); + cb.include_file(included_file.name()); } - ctx.add_dep(included_file.into_boxed_str()); + ctx.add_dep(included_file); + } + None => { + warn!("Inclusion of a nameless file in {:?}", cursor) } } Err(ParseError::Continue) diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs index 9d46135f74..c4960d7e6c 100644 --- a/bindgen/ir/var.rs +++ b/bindgen/ir/var.rs @@ -479,10 +479,11 @@ fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option { value } +#[cfg_attr(not(feature = "experimental"), allow(unused_variables))] fn duplicated_macro_diagnostic( macro_name: &str, - _location: crate::clang::SourceLocation, - _ctx: &BindgenContext, + location: crate::clang::SourceLocation, + ctx: &BindgenContext, ) { warn!("Duplicated macro definition: {}", macro_name); @@ -500,19 +501,21 @@ fn duplicated_macro_diagnostic( // // Will trigger this message even though there's nothing wrong with it. #[allow(clippy::overly_complex_bool_expr)] - if false && _ctx.options().emit_diagnostics { + if false && ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; use std::borrow::Cow; let mut slice = Slice::default(); let mut source = Cow::from(macro_name); - let (file, line, col, _) = _location.location(); - if let Some(filename) = file.name() { - if let Ok(Some(code)) = get_line(&filename, line) { + if let crate::clang::SourceLocation::File { + file, line, column, .. + } = location + { + if let Ok(Some(code)) = get_line(file.path(), line) { source = code.into(); } - slice.with_location(filename, line, col); + slice.with_location(file.name(), line, column); } slice.with_source(source);