From 83f729f44819459665832459cb86b68b4fc3739f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 9 Jun 2023 13:57:05 +0200 Subject: [PATCH] Parse code by source order. (#2543) --- CHANGELOG.md | 2 + .../expectations/tests/allowlist-file.rs | 2 +- .../expectations/tests/jsval_layout_opaque.rs | 4 +- .../tests/jsval_layout_opaque_1_0.rs | 4 +- .../tests/expectations/tests/layout_arp.rs | 14 +-- .../tests/expectations/tests/layout_array.rs | 14 +-- .../expectations/tests/layout_eth_conf.rs | 50 +++++----- .../expectations/tests/layout_eth_conf_1_0.rs | 50 +++++----- .../tests/expectations/tests/namespace.rs | 4 +- ...mplate_instantiation_with_fn_local_type.rs | 30 +++--- bindgen/clang.rs | 97 +++++++++++++++++++ bindgen/deps.rs | 2 +- bindgen/ir/context.rs | 38 ++++++-- bindgen/ir/item.rs | 8 +- bindgen/ir/module.rs | 5 +- bindgen/lib.rs | 7 +- 16 files changed, 231 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93072cb4e7..610c2cfcca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -188,6 +188,8 @@ * Updated `bitflags` dependency to 2.2.1. This changes the API of `CodegenConfig`. * Prettyplease formatting is gated by an optional, enabled by default Cargo feature when depending on `bindgen` as a library. +* Items are now parsed in the order they appear in source files. This may result in + auto-generated `_bindgen_*` names having a different index. ## Removed diff --git a/bindgen-tests/tests/expectations/tests/allowlist-file.rs b/bindgen-tests/tests/expectations/tests/allowlist-file.rs index 1ee7a192ed..63953ccb67 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/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs index cfbf2f61cc..4ec58e7825 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 b97bbac96f..fa55d5c1ce 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 1ee045593f..ee6bdf01a8 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 @@ -133,3 +126,10 @@ fn bindgen_test_layout_arp_hdr() { stringify!(arp_data)) ); } +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 d9171be24b..3654c62c7c 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), @@ -118,6 +116,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)] @@ -199,6 +198,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 1ec0744f0d..0916a16b85 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.*/ @@ -1214,6 +1189,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)] @@ -1286,6 +1263,29 @@ fn bindgen_test_layout_rte_eth_fdir_flex_mask() { stringify!(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 086384c450..c20732c604 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.*/ @@ -1327,6 +1302,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)] @@ -1409,6 +1386,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 83543b851e..a99711b277 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)] @@ -46,7 +46,7 @@ pub mod root { #[repr(C)] #[derive(Debug)] pub struct C { - 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/template_instantiation_with_fn_local_type.rs b/bindgen-tests/tests/expectations/tests/template_instantiation_with_fn_local_type.rs index ab87b4160b..5816a6c5e9 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(); -} #[test] fn __bindgen_test_layout_Foo_open0_Bar_close0_instantiation() { assert_eq!( @@ -19,6 +15,21 @@ fn __bindgen_test_layout_Foo_open0_Bar_close0_instantiation() { concat!("Alignment of template specialization: ", stringify!(Foo)) ); } +#[test] +fn __bindgen_test_layout_Foo_open0_Boo_close0_instantiation() { + assert_eq!( + ::std::mem::size_of:: < Foo > (), 1usize, + concat!("Size of template specialization: ", stringify!(Foo)) + ); + assert_eq!( + ::std::mem::align_of:: < Foo > (), 1usize, + concat!("Alignment of template specialization: ", stringify!(Foo)) + ); +} +extern "C" { + #[link_name = "\u{1}_Z1fv"] + pub fn f(); +} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Baz { @@ -34,17 +45,6 @@ fn bindgen_test_layout_Baz() { stringify!(Baz)) ); } -#[test] -fn __bindgen_test_layout_Foo_open0_Boo_close0_instantiation() { - assert_eq!( - ::std::mem::size_of:: < Foo > (), 1usize, - concat!("Size of template specialization: ", stringify!(Foo)) - ); - assert_eq!( - ::std::mem::align_of:: < Foo > (), 1usize, - concat!("Alignment of template specialization: ", stringify!(Foo)) - ); -} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Bar { diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 0060213336..0559faf464 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -6,6 +6,8 @@ use crate::ir::context::BindgenContext; use clang_sys::*; +use std::cmp; + use std::ffi::{CStr, CString}; use std::fmt; use std::hash::Hash; @@ -496,6 +498,44 @@ impl Cursor { } } + /// Traverse this curser's children, sorted by where they appear in source code. + /// + /// Call the given function on each AST node traversed. + pub(crate) fn visit_sorted( + &self, + ctx: &mut BindgenContext, + mut visitor: Visitor, + ) where + Visitor: FnMut(&mut BindgenContext, Cursor) -> CXChildVisitResult, + { + 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); + } + } + } + } + + children.sort_by(|child1, child2| { + child1 + .location() + .partial_cmp_with_context(&child2.location(), ctx) + .unwrap_or(std::cmp::Ordering::Equal) + }); + + for child in children { + visitor(ctx, child); + } + } + /// Collect all of this cursor's children into a vec and return them. pub(crate) fn collect_children(&self) -> Vec { let mut children = vec![]; @@ -1524,6 +1564,63 @@ impl SourceLocation { } } +impl SourceLocation { + /// Compare source locations, also 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. + pub(crate) fn partial_cmp_with_context( + &self, + other: &Self, + ctx: &BindgenContext, + ) -> Option { + let (file, _, _, offset) = self.location(); + let (other_file, _, _, other_offset) = other.location(); + + match (file.name(), other_file.name()) { + (Some(file), Some(other_file)) => { + if file == other_file { + return offset.partial_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.partial_cmp(&other_offset) + } + (Some(_), None) => Some(cmp::Ordering::Greater), + (_, Some((other_file2, other_offset2))) + if file == other_file2 => + { + offset.partial_cmp(&other_offset2) + } + (None, Some(_)) => Some(cmp::Ordering::Less), + ( + Some((file2, offset2)), + Some((other_file2, other_offset2)), + ) => { + if file2 == other_file2 { + offset2.partial_cmp(&other_offset2) + } else { + None + } + } + (None, None) => Some(cmp::Ordering::Equal), + } + } + // Built-in definitions should come first. + (Some(_), None) => Some(cmp::Ordering::Greater), + (None, Some(_)) => Some(cmp::Ordering::Less), + (None, None) => Some(cmp::Ordering::Equal), + } + } +} + impl fmt::Display for SourceLocation { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (file, line, col, _) = self.location(); diff --git a/bindgen/deps.rs b/bindgen/deps.rs index 2edeaa8886..e348fa1303 100644 --- a/bindgen/deps.rs +++ b/bindgen/deps.rs @@ -9,7 +9,7 @@ pub(crate) struct DepfileSpec { impl DepfileSpec { pub fn write(&self, deps: &BTreeSet) -> std::io::Result<()> { - std::fs::write(&self.depfile_path, &self.to_string(deps)) + std::fs::write(&self.depfile_path, self.to_string(deps)) } fn to_string(&self, deps: &BTreeSet) -> String { diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index ee07625430..bc9e59c3f0 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -356,6 +356,14 @@ pub(crate) struct BindgenContext { /// This needs to be an std::HashMap because the cexpr API requires it. parsed_macros: StdHashMap, cexpr::expr::EvalResult>, + /// A map with all include locations. + /// + /// This is needed so that items are created in the order they are defined in. + /// + /// 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, + /// A set of all the included filenames. deps: BTreeSet, @@ -560,6 +568,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" BindgenContext { items: vec![Some(root_module)], + includes: Default::default(), deps, types: Default::default(), type_params: Default::default(), @@ -634,12 +643,29 @@ If you encounter an error missing from this list, please file an issue or a PR!" ) } - /// Add another path to the set of included files. - pub(crate) fn include_file(&mut self, filename: String) { - for cb in &self.options().parse_callbacks { - cb.include_file(&filename); - } - self.deps.insert(filename); + /// Add the location of the `#include` directive for the `included_file`. + pub(crate) fn add_include( + &mut self, + source_file: String, + included_file: String, + offset: usize, + ) { + self.includes + .entry(included_file) + .or_insert((source_file, offset)); + } + + /// Get the location of the first `#include` directive for the `included_file`. + pub(crate) fn included_file_location( + &self, + included_file: &str, + ) -> Option<(String, usize)> { + self.includes.get(included_file).cloned() + } + + /// Add an included file. + pub(crate) fn add_dep(&mut self, dep: String) { + self.deps.insert(dep); } /// Get any included files. diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs index f4dce45d83..1b9d7694b2 100644 --- a/bindgen/ir/item.rs +++ b/bindgen/ir/item.rs @@ -1460,8 +1460,12 @@ impl Item { cursor ); } - Some(filename) => { - ctx.include_file(filename); + Some(included_file) => { + for cb in &ctx.options().parse_callbacks { + cb.include_file(&included_file); + } + + ctx.add_dep(included_file); } } } diff --git a/bindgen/ir/module.rs b/bindgen/ir/module.rs index f25ef40f77..5ec55e9048 100644 --- a/bindgen/ir/module.rs +++ b/bindgen/ir/module.rs @@ -6,6 +6,7 @@ use super::item::ItemSet; use crate::clang; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use crate::parse_one; + use std::io; /// Whether this module is inline or not. @@ -82,8 +83,8 @@ impl ClangSubItemParser for Module { CXCursor_Namespace => { let module_id = ctx.module(cursor); ctx.with_module(module_id, |ctx| { - cursor.visit(|cursor| { - parse_one(ctx, cursor, Some(module_id.into())) + cursor.visit_sorted(ctx, |ctx, child| { + parse_one(ctx, child, Some(module_id.into())) }) }); diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 2eb4486dac..be0cd8266a 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -1085,7 +1085,8 @@ fn parse_one( Ok(..) => {} Err(ParseError::Continue) => {} Err(ParseError::Recurse) => { - cursor.visit(|child| parse_one(ctx, child, parent)); + cursor + .visit_sorted(ctx, |ctx, child| parse_one(ctx, child, parent)); } } CXChildVisit_Continue @@ -1126,8 +1127,8 @@ fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> { } let root = context.root_module(); - context.with_module(root, |context| { - cursor.visit(|cursor| parse_one(context, cursor, None)) + context.with_module(root, |ctx| { + cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, None)) }); assert!(