diff --git a/bindgen/clang.rs b/bindgen/clang.rs
index c1e7e38e36..6f37a9b719 100644
--- a/bindgen/clang.rs
+++ b/bindgen/clang.rs
@@ -4,7 +4,7 @@
 #![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::cmp;
 
@@ -552,32 +552,145 @@ impl Cursor {
             return offset.cmp(&other_offset);
         }
 
-        // `None` here means `file`/`other_file` is the main header file.
-        let include_location = ctx.included_file_location(&file);
-        let other_include_location = ctx.included_file_location(&other_file);
+        let mut include_location = ctx.included_file_location(&file);
+        let mut other_include_location =
+            ctx.included_file_location(&other_file);
 
-        match (include_location, other_include_location) {
-            // The main header file (`None`) comes after header passed as CLI argument (`Some((None, _))`).
-            (None, Some((None, _))) => cmp::Ordering::Greater,
-            (Some((None, _)), None) => cmp::Ordering::Less,
-            // If an item was included in the same source file as the other item,
-            // compare its `#include` location offset the offset of the other item.
-            (Some((Some(file2), offset2)), _) if file2 == other_file => {
-                offset2.cmp(&other_offset)
-            }
-            (_, Some((Some(other_file2), other_offset2)))
-                if file == other_file2 =>
-            {
-                offset.cmp(&other_offset2)
-            }
-            // If both items were included in the same file, compare the offset of their `#include` directives.
-            (Some((file2, offset2)), Some((other_file2, other_offset2)))
-                if file2 == other_file2 =>
-            {
-                offset2.cmp(&other_offset2)
+        use IncludeLocation::*;
+
+        loop {
+            match (&include_location, &other_include_location) {
+                // Both items are in the main header file, this should already have been handled at this point.
+                (Main, Main) => {
+                    unreachable!("Should have been handled at this point.")
+                }
+                // Headers passed as CLI arguments come before the main header file.
+                (Main, Cli { .. }) => return cmp::Ordering::Greater,
+                (Cli { .. }, Main) => return cmp::Ordering::Less,
+                // If both were included via CLI arguments, compare their offset.
+                (
+                    Cli { offset: offset2 },
+                    Cli {
+                        offset: other_offset2,
+                    },
+                ) => return offset2.cmp(&other_offset2),
+                // If an item was included in the same source file as the other item,
+                // compare its `#include` location offset the offset of the other item.
+                (
+                    File {
+                        file_name: ref file2,
+                        offset: offset2,
+                    },
+                    Main,
+                ) => {
+                    if *file2 == other_file {
+                        return offset2.cmp(&other_offset);
+                    }
+
+                    // Continue checking one level up.
+                    include_location = ctx.included_file_location(&file2);
+                }
+                (
+                    Main,
+                    File {
+                        file_name: ref other_file2,
+                        offset: other_offset2,
+                    },
+                ) => {
+                    if file == *other_file2 {
+                        return offset.cmp(&other_offset2);
+                    }
+
+                    // Continue checking one level up.
+                    other_include_location =
+                        ctx.included_file_location(&other_file2);
+                }
+                (
+                    File {
+                        file_name: file2,
+                        offset: offset2,
+                    },
+                    File {
+                        file_name: other_file2,
+                        offset: other_offset2,
+                    },
+                ) => {
+                    // If both items were included in the same file, compare the offset of their `#include` directives.
+                    if file2 == other_file2 {
+                        return offset2.cmp(&other_offset2);
+                    }
+
+                    // Find the offset of where `file` is transivitely included in `ancestor_file`.
+                    let offset_in_ancestor =
+                        |mut file: String, ancestor_file: &str| {
+                            while file != ancestor_file {
+                                let mut include_location =
+                                    ctx.included_file_location(&file);
+                                file = if let IncludeLocation::File {
+                                    file_name: file,
+                                    offset,
+                                } = include_location
+                                {
+                                    if file == ancestor_file {
+                                        return Some(offset);
+                                    }
+
+                                    file
+                                } else {
+                                    break;
+                                }
+                            }
+
+                            None
+                        };
+
+                    if let Some(offset2) =
+                        offset_in_ancestor(file2.clone(), &other_file2)
+                    {
+                        return offset2.cmp(&other_offset2);
+                    }
+
+                    if let Some(other_offset2) =
+                        offset_in_ancestor(other_file2.clone(), &file2)
+                    {
+                        return offset2.cmp(&other_offset2);
+                    }
+
+                    // Otherwise, go one level up.
+                    //
+                    // # Example
+                    //
+                    // a.h
+                    // ├── b.h
+                    // └── c.h
+                    //
+                    // When comparing items inside `b.h` and `c.h`, go up one level and
+                    // compare the include locations of `b.h` and `c.h` in `a.h` instead.
+                    include_location = ctx.included_file_location(file2);
+                    other_include_location =
+                        ctx.included_file_location(other_file2);
+                }
+                (
+                    File {
+                        file_name: file2, ..
+                    },
+                    Cli { .. },
+                ) => {
+                    // Continue checking one level up.
+                    include_location = ctx.included_file_location(&file2);
+                }
+                (
+                    Cli { .. },
+                    File {
+                        file_name: other_file2,
+                        ..
+                    },
+                ) => {
+                    // Continue checking one level up.
+                    other_include_location =
+                        ctx.included_file_location(&other_file2);
+                }
             }
-            // Otherwise, keep the original sorting.
-            _ => cmp::Ordering::Equal,
         }
     }
 
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index 87af398f1b..c59cad4c54 100644
--- a/bindgen/ir/context.rs
+++ b/bindgen/ir/context.rs
@@ -305,6 +305,14 @@ enum TypeKey {
     Declaration(Cursor),
 }
 
+/// Specifies where a header was included from.
+#[derive(Debug)]
+pub(crate) enum IncludeLocation {
+    Main,
+    Cli { offset: usize },
+    File { file_name: String, offset: usize },
+}
+
 /// A context used during parsing and generation of structs.
 #[derive(Debug)]
 pub(crate) struct BindgenContext {
@@ -659,8 +667,17 @@ If you encounter an error missing from this list, please file an issue or a PR!"
     pub(crate) fn included_file_location(
         &self,
         included_file: &str,
-    ) -> Option<(Option<String>, usize)> {
-        self.includes.get(included_file).cloned()
+    ) -> IncludeLocation {
+        match self.includes.get(included_file).cloned() {
+            // Header was not included anywhere, so it must be the main header.
+            None => IncludeLocation::Main,
+            // Header has no source location, so it must have been included via CLI arguments.
+            Some((None, offset)) => IncludeLocation::Cli { offset },
+            // Header was included with an `#include` directive.
+            Some((Some(file_name), offset)) => {
+                IncludeLocation::File { file_name, offset }
+            }
+        }
     }
 
     /// Add an included file.