Repository: rust-lang/rust-bindgen
Pull request #2528 (2023-05-22 19:56:08)

fix and simplify language


Patch:
diff --git a/.github/workflows/bindgen.yml b/.github/workflows/bindgen.yml
index 8ab00dce..72a34fa0 100644
--- a/.github/workflows/bindgen.yml
+++ b/.github/workflows/bindgen.yml
@@ -111,8 +111,6 @@ jobs:
     runs-on: ${{matrix.os}}
     strategy:
       matrix:
-        # TODO(#1954): These should be run on mac too, but turns out they're
-        # broken.
         os: [ubuntu-latest, macos-latest]
     steps:
       - uses: actions/checkout@v3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a611ea40..650d055c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -170,6 +170,8 @@
   instead of `&[u8]`. (Requires Rust 1.59 or higher.)
 * Added the `--generate-shell-completions` CLI flag to generate completions for
   different shells.
+* The `--wrap-static-fns` option can now wrap `va_list` functions as variadic functions
+  with the experimental `wrap_as_variadic_fn` callback.
 
 ## Changed
 
@@ -184,7 +186,18 @@
   them. To make the escaping clear and consistent, backslashes are also
   escaped.
 * 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.
+* Remove redundant Cargo features, which were all implicit:
+  - bindgen-cli: `env_logger` and `log` removed in favor of `logging`
+  - bindgen (lib):
+    + `log` removed in favor of `logging`
+    + `which` removed in favor of `which-logging`
+    + `annotate-snippets` removed in favor of `experimental`
+* Add target mappings for riscv32imc and riscv32imac.
+
 ## Removed
 
 ## Fixed
diff --git a/bindgen-cli/Cargo.toml b/bindgen-cli/Cargo.toml
index 523a01b7..90e8cc62 100644
--- a/bindgen-cli/Cargo.toml
+++ b/bindgen-cli/Cargo.toml
@@ -21,15 +21,15 @@ name = "bindgen"
 
 [dependencies]
 bindgen = { path = "../bindgen", version = "=0.65.1", features = ["__cli", "experimental"] }
-shlex = "1"
 clap = { version = "4", features = ["derive"] }
 clap_complete = "4"
 env_logger = { version = "0.10.0", optional = true }
 log = { version = "0.4", optional = true }
+shlex = "1"
 
 [features]
 default = ["logging", "runtime", "which-rustfmt"]
-logging = ["bindgen/logging", "env_logger", "log"]
+logging = ["bindgen/logging", "dep:env_logger", "dep:log"]
 static = ["bindgen/static"]
 runtime = ["bindgen/runtime"]
 # Dynamically discover a `rustfmt` binary using the `which` crate
diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs
index e03f7f9a..ce4a3200 100644
--- a/bindgen-integration/build.rs
+++ b/bindgen-integration/build.rs
@@ -149,6 +149,15 @@ impl Drop for MacroCallback {
     }
 }
 
+#[derive(Debug)]
+struct WrappedVaListCallback;
+
+impl ParseCallbacks for WrappedVaListCallback {
+    fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
+        Some(name.to_owned() + "_wrapped")
+    }
+}
+
 fn setup_macro_test() {
     cc::Build::new()
         .cpp(true)
@@ -223,10 +232,12 @@ fn setup_wrap_static_fns_test() {
     let bindings = Builder::default()
         .header(input_header_file_path_str)
         .parse_callbacks(Box::new(CargoCallbacks))
+        .parse_callbacks(Box::new(WrappedVaListCallback))
         .wrap_static_fns(true)
         .wrap_static_fns_path(
             out_path.join("wrap_static_fns").display().to_string(),
         )
+        .clang_arg("-DUSE_VA_HEADER")
         .generate()
         .expect("Unable to generate bindings");
 
@@ -242,6 +253,7 @@ fn setup_wrap_static_fns_test() {
         .arg("-o")
         .arg(&obj_path)
         .arg(out_path.join("wrap_static_fns.c"))
+        .arg("-DUSE_VA_HEADER")
         .output()
         .expect("`clang` command error");
     if !clang_output.status.success() {
diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs
index e89351c3..04f6a5c9 100755
--- a/bindgen-integration/src/lib.rs
+++ b/bindgen-integration/src/lib.rs
@@ -320,5 +320,13 @@ fn test_wrap_static_fns() {
         let tq =
             extern_bindings::takes_qualified(&(&5 as *const _) as *const _);
         assert_eq!(5, tq);
+
+        let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(0);
+        assert_eq!(0, wv1);
+
+        let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(2, 5, 3);
+        assert_eq!(8, wv1);
+
+        extern_bindings::wrap_as_variadic_fn2_wrapped(1, 2);
     }
 }
diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml
index fd20049e..054c841f 100644
--- a/bindgen/Cargo.toml
+++ b/bindgen/Cargo.toml
@@ -25,31 +25,31 @@ name = "bindgen"
 path = "lib.rs"
 
 [dependencies]
+annotate-snippets = { version = "0.9.1", features = ["color"], optional = true }
 bitflags = "2.2.1"
 cexpr = "0.6"
 clang-sys = { version = "1", features = ["clang_6_0"] }
-lazycell = "1"
 lazy_static = "1"
+lazycell = "1"
+log = { version = "0.4", optional = true }
 peeking_take_while = "0.1.2"
+prettyplease = { version = "0.2.0", optional = true }
+proc-macro2 = { version = "1", default-features = false }
 quote = { version = "1", default-features = false }
-syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"]}
-regex = { version = "1.5", default-features = false , features = ["std", "unicode"] }
-which = { version = "4.2.1", optional = true, default-features = false }
-prettyplease = { version = "0.2.0" }
-annotate-snippets = { version = "0.9.1", features = ["color"], optional = true }
-shlex = "1"
+regex = { version = "1.5", default-features = false, features = ["std", "unicode"] }
 rustc-hash = "1.0.1"
-proc-macro2 = { version = "1", default-features = false }
-log = { version = "0.4", optional = true }
+shlex = "1"
+syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] }
+which = { version = "4.2.1", optional = true, default-features = false }
 
 [features]
-default = ["logging", "runtime", "which-rustfmt"]
-logging = ["log"]
+default = ["logging", "prettyplease", "runtime", "which-rustfmt"]
+logging = ["dep:log"]
 static = ["clang-sys/static"]
 runtime = ["clang-sys/runtime"]
 # Dynamically discover a `rustfmt` binary using the `which` crate
-which-rustfmt = ["which"]
-experimental = ["annotate-snippets"]
+which-rustfmt = ["dep:which"]
+experimental = ["dep:annotate-snippets"]
 
 ## The following features are for internal use and they shouldn't be used if
 ## you're not hacking on bindgen
diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs
index 58244668..a9d315dc 100644
--- a/bindgen/callbacks.rs
+++ b/bindgen/callbacks.rs
@@ -135,6 +135,27 @@ pub trait ParseCallbacks: fmt::Debug {
     fn process_comment(&self, _comment: &str) -> Option<String> {
         None
     }
+
+    /// Potentially override the visibility of a composite type field.
+    ///
+    /// Caution: This allows overriding standard C++ visibility inferred by
+    /// `respect_cxx_access_specs`.
+    fn field_visibility(
+        &self,
+        _info: FieldInfo<'_>,
+    ) -> Option<crate::FieldVisibilityKind> {
+        None
+    }
+
+    /// Process a function name that as exactly one `va_list` argument
+    /// to be wrapped as a variadic function with the wrapped static function
+    /// feature.
+    ///
+    /// The returned string is new function name.
+    #[cfg(feature = "experimental")]
+    fn wrap_as_variadic_fn(&self, _name: &str) -> Option<String> {
+        None
+    }
 }
 
 /// Relevant information about a type to which new derive attributes will be added using
@@ -176,3 +197,14 @@ pub enum ItemKind {
     /// A Variable
     Var,
 }
+
+/// Relevant information about a field for which visibility can be determined using
+/// [`ParseCallbacks::field_visibility`].
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct FieldInfo<'a> {
+    /// The name of the type.
+    pub type_name: &'a str,
+    /// The name of the field.
+    pub field_name: &'a str,
+}
diff --git a/bindgen/clang.rs b/bindgen/clang.rs
index 00602133..0559faf4 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<Visitor>(
+        &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<Cursor> {
         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<cmp::Ordering> {
+        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/codegen/mod.rs b/bindgen/codegen/mod.rs
index 47f23193..c381f57c 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -19,7 +19,7 @@ use self::struct_layout::StructLayoutTracker;
 
 use super::BindgenOptions;
 
-use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind};
+use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind};
 use crate::ir::analysis::{HasVtable, Sizedness};
 use crate::ir::annotations::{
     Annotations, FieldAccessorKind, FieldVisibilityKind,
@@ -221,6 +221,11 @@ impl From<DerivableTraits> for Vec<&'static str> {
     }
 }
 
+struct WrapAsVariadic {
+    new_name: String,
+    idx_of_va_list_arg: usize,
+}
+
 struct CodegenResult<'a> {
     items: Vec<proc_macro2::TokenStream>,
     dynamic_items: DynamicItems,
@@ -269,7 +274,9 @@ struct CodegenResult<'a> {
     /// that name. This lets us give each overload a unique suffix.
     overload_counters: HashMap<String, u32>,
 
-    items_to_serialize: Vec<ItemId>,
+    /// List of items to serialize. With optionally the argument for the wrap as
+    /// variadic transformation to be applied.
+    items_to_serialize: Vec<(ItemId, Option<WrapAsVariadic>)>,
 }
 
 impl<'a> CodegenResult<'a> {
@@ -1291,6 +1298,7 @@ trait FieldCodegen<'a> {
         visibility_kind: FieldVisibilityKind,
         accessor_kind: FieldAccessorKind,
         parent: &CompInfo,
+        parent_item: &Item,
         result: &mut CodegenResult,
         struct_layout: &mut StructLayoutTracker,
         fields: &mut F,
@@ -1310,6 +1318,7 @@ impl<'a> FieldCodegen<'a> for Field {
         visibility_kind: FieldVisibilityKind,
         accessor_kind: FieldAccessorKind,
         parent: &CompInfo,
+        parent_item: &Item,
         result: &mut CodegenResult,
         struct_layout: &mut StructLayoutTracker,
         fields: &mut F,
@@ -1326,6 +1335,7 @@ impl<'a> FieldCodegen<'a> for Field {
                     visibility_kind,
                     accessor_kind,
                     parent,
+                    parent_item,
                     result,
                     struct_layout,
                     fields,
@@ -1339,6 +1349,7 @@ impl<'a> FieldCodegen<'a> for Field {
                     visibility_kind,
                     accessor_kind,
                     parent,
+                    parent_item,
                     result,
                     struct_layout,
                     fields,
@@ -1388,6 +1399,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
         parent_visibility_kind: FieldVisibilityKind,
         accessor_kind: FieldAccessorKind,
         parent: &CompInfo,
+        parent_item: &Item,
         result: &mut CodegenResult,
         struct_layout: &mut StructLayoutTracker,
         fields: &mut F,
@@ -1440,10 +1452,11 @@ impl<'a> FieldCodegen<'a> for FieldData {
             .name()
             .map(|name| ctx.rust_mangle(name).into_owned())
             .expect("Each field should have a name in codegen!");
-        let field_ident = ctx.rust_ident_raw(field_name.as_str());
+        let field_name = field_name.as_str();
+        let field_ident = ctx.rust_ident_raw(field_name);
 
         if let Some(padding_field) =
-            struct_layout.saw_field(&field_name, field_ty, self.offset())
+            struct_layout.saw_field(field_name, field_ty, self.offset())
         {
             fields.extend(Some(padding_field));
         }
@@ -1451,7 +1464,13 @@ impl<'a> FieldCodegen<'a> for FieldData {
         let visibility = compute_visibility(
             ctx,
             self.is_public(),
-            Some(self.annotations()),
+            ctx.options().last_callback(|cb| {
+                cb.field_visibility(FieldInfo {
+                    type_name: &parent_item.canonical_name(ctx),
+                    field_name,
+                })
+            }),
+            self.annotations(),
             parent_visibility_kind,
         );
         let accessor_kind =
@@ -1485,7 +1504,6 @@ impl<'a> FieldCodegen<'a> for FieldData {
         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);
 
         methods.extend(Some(match accessor_kind {
             FieldAccessorKind::None => unreachable!(),
@@ -1493,12 +1511,12 @@ impl<'a> FieldCodegen<'a> for FieldData {
                 quote! {
                     #[inline]
                     pub fn #getter_name(&self) -> & #ty {
-                        &self.#field_name
+                        &self.#field_ident
                     }
 
                     #[inline]
                     pub fn #mutable_getter_name(&mut self) -> &mut #ty {
-                        &mut self.#field_name
+                        &mut self.#field_ident
                     }
                 }
             }
@@ -1506,12 +1524,12 @@ impl<'a> FieldCodegen<'a> for FieldData {
                 quote! {
                     #[inline]
                     pub unsafe fn #getter_name(&self) -> & #ty {
-                        &self.#field_name
+                        &self.#field_ident
                     }
 
                     #[inline]
                     pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty {
-                        &mut self.#field_name
+                        &mut self.#field_ident
                     }
                 }
             }
@@ -1519,7 +1537,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
                 quote! {
                     #[inline]
                     pub fn #getter_name(&self) -> & #ty {
-                        &self.#field_name
+                        &self.#field_ident
                     }
                 }
             }
@@ -1604,27 +1622,28 @@ fn access_specifier(
 fn compute_visibility(
     ctx: &BindgenContext,
     is_declared_public: bool,
-    annotations: Option<&Annotations>,
+    callback_override: Option<FieldVisibilityKind>,
+    annotations: &Annotations,
     default_kind: FieldVisibilityKind,
 ) -> FieldVisibilityKind {
-    match (
-        is_declared_public,
-        ctx.options().respect_cxx_access_specs,
-        annotations.and_then(|e| e.visibility_kind()),
-    ) {
-        (true, true, annotated_visibility) => {
-            // declared as public, cxx specs are respected
-            annotated_visibility.unwrap_or(FieldVisibilityKind::Public)
-        }
-        (false, true, annotated_visibility) => {
-            // declared as private, cxx specs are respected
-            annotated_visibility.unwrap_or(FieldVisibilityKind::Private)
-        }
-        (_, false, annotated_visibility) => {
-            // cxx specs are not respected, declaration does not matter.
-            annotated_visibility.unwrap_or(default_kind)
-        }
-    }
+    callback_override
+        .or_else(|| annotations.visibility_kind())
+        .unwrap_or_else(|| {
+            match (is_declared_public, ctx.options().respect_cxx_access_specs) {
+                (true, true) => {
+                    // declared as public, cxx specs are respected
+                    FieldVisibilityKind::Public
+                }
+                (false, true) => {
+                    // declared as private, cxx specs are respected
+                    FieldVisibilityKind::Private
+                }
+                (_, false) => {
+                    // cxx specs are not respected, declaration does not matter.
+                    default_kind
+                }
+            }
+        })
 }
 
 impl<'a> FieldCodegen<'a> for BitfieldUnit {
@@ -1636,6 +1655,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
         visibility_kind: FieldVisibilityKind,
         accessor_kind: FieldAccessorKind,
         parent: &CompInfo,
+        parent_item: &Item,
         result: &mut CodegenResult,
         struct_layout: &mut StructLayoutTracker,
         fields: &mut F,
@@ -1695,7 +1715,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
         // the 32 items limitation.
         let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
 
-        let mut all_fields_declared_as_public = true;
+        let mut unit_visibility = visibility_kind;
         for bf in self.bitfields() {
             // Codegen not allowed for anonymous bitfields
             if bf.name().is_none() {
@@ -1708,19 +1728,27 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
                 continue;
             }
 
-            all_fields_declared_as_public &= bf.is_public();
             let mut bitfield_representable_as_int = true;
+            let mut bitfield_visibility = visibility_kind;
             bf.codegen(
                 ctx,
                 visibility_kind,
                 accessor_kind,
                 parent,
+                parent_item,
                 result,
                 struct_layout,
                 fields,
                 methods,
-                (&unit_field_name, &mut bitfield_representable_as_int),
+                (
+                    &unit_field_name,
+                    &mut bitfield_representable_as_int,
+                    &mut bitfield_visibility,
+                ),
             );
+            if bitfield_visibility < unit_visibility {
+                unit_visibility = bitfield_visibility;
+            }
 
             // Generating a constructor requires the bitfield to be representable as an integer.
             if !bitfield_representable_as_int {
@@ -1740,13 +1768,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
             ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
         }
 
-        let visibility_kind = compute_visibility(
-            ctx,
-            all_fields_declared_as_public,
-            None,
-            visibility_kind,
-        );
-        let access_spec = access_specifier(visibility_kind);
+        let access_spec = access_specifier(unit_visibility);
 
         let field = quote! {
             #access_spec #unit_field_ident : #field_ty ,
@@ -1787,7 +1809,7 @@ fn bitfield_setter_name(
 }
 
 impl<'a> FieldCodegen<'a> for Bitfield {
-    type Extra = (&'a str, &'a mut bool);
+    type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind);
 
     fn codegen<F, M>(
         &self,
@@ -1795,11 +1817,16 @@ impl<'a> FieldCodegen<'a> for Bitfield {
         visibility_kind: FieldVisibilityKind,
         _accessor_kind: FieldAccessorKind,
         parent: &CompInfo,
+        parent_item: &Item,
         _result: &mut CodegenResult,
         struct_layout: &mut StructLayoutTracker,
         _fields: &mut F,
         methods: &mut M,
-        (unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool),
+        (unit_field_name, bitfield_representable_as_int, bitfield_visibility): (
+            &'a str,
+            &mut bool,
+            &'a mut FieldVisibilityKind,
+        ),
     ) where
         F: Extend<proc_macro2::TokenStream>,
         M: Extend<proc_macro2::TokenStream>,
@@ -1833,13 +1860,22 @@ impl<'a> FieldCodegen<'a> for Bitfield {
         let offset = self.offset_into_unit();
         let width = self.width() as u8;
 
-        let visibility_kind = compute_visibility(
+        let override_visibility = self.name().and_then(|field_name| {
+            ctx.options().last_callback(|cb| {
+                cb.field_visibility(FieldInfo {
+                    type_name: &parent_item.canonical_name(ctx),
+                    field_name,
+                })
+            })
+        });
+        *bitfield_visibility = compute_visibility(
             ctx,
             self.is_public(),
-            Some(self.annotations()),
+            override_visibility,
+            self.annotations(),
             visibility_kind,
         );
-        let access_spec = access_specifier(visibility_kind);
+        let access_spec = access_specifier(*bitfield_visibility);
 
         if parent.is_union() && !struct_layout.is_rust_union() {
             methods.extend(Some(quote! {
@@ -1933,8 +1969,17 @@ impl CodeGenerator for CompInfo {
         // the parent too.
         let is_opaque = item.is_opaque(ctx, &());
         let mut fields = vec![];
-        let mut struct_layout =
-            StructLayoutTracker::new(ctx, self, ty, &canonical_name);
+        let visibility = item
+            .annotations()
+            .visibility_kind()
+            .unwrap_or(ctx.options().default_visibility);
+        let mut struct_layout = StructLayoutTracker::new(
+            ctx,
+            self,
+            ty,
+            &canonical_name,
+            visibility,
+        );
 
         if !is_opaque {
             if item.has_vtable_ptr(ctx) {
@@ -1983,10 +2028,6 @@ impl CodeGenerator for CompInfo {
 
         let mut methods = vec![];
         if !is_opaque {
-            let visibility = item
-                .annotations()
-                .visibility_kind()
-                .unwrap_or(ctx.options().default_visibility);
             let struct_accessor_kind = item
                 .annotations()
                 .accessor_kind()
@@ -1997,6 +2038,7 @@ impl CodeGenerator for CompInfo {
                     visibility,
                     struct_accessor_kind,
                     self,
+                    item,
                     result,
                     &mut struct_layout,
                     &mut fields,
@@ -4211,9 +4253,6 @@ impl CodeGenerator for Function {
             result.saw_function(seen_symbol_name);
         }
 
-        let args = utils::fnsig_arguments(ctx, signature);
-        let ret = utils::fnsig_return_ty(ctx, signature);
-
         let mut attributes = vec![];
 
         if ctx.options().rust_features().must_use_function {
@@ -4298,10 +4337,6 @@ impl CodeGenerator for Function {
             abi => abi,
         };
 
-        if is_internal && ctx.options().wrap_static_fns {
-            result.items_to_serialize.push(item.id());
-        }
-
         // Handle overloaded functions by giving each overload its own unique
         // suffix.
         let times_seen = result.overload_number(&canonical_name);
@@ -4335,12 +4370,49 @@ impl CodeGenerator for Function {
                 quote! { #[link(wasm_import_module = #name)] }
             });
 
-        if is_internal && ctx.options().wrap_static_fns && !has_link_name_attr {
+        let should_wrap =
+            is_internal && ctx.options().wrap_static_fns && !has_link_name_attr;
+
+        if should_wrap {
             let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
             attributes.push(attributes::link_name::<true>(&name));
         }
 
-        let ident = ctx.rust_ident(canonical_name);
+        let wrap_as_variadic = if should_wrap && !signature.is_variadic() {
+            utils::wrap_as_variadic_fn(ctx, signature, name)
+        } else {
+            None
+        };
+
+        let (ident, args) = if let Some(WrapAsVariadic {
+            idx_of_va_list_arg,
+            new_name,
+        }) = &wrap_as_variadic
+        {
+            (
+                new_name,
+                utils::fnsig_arguments_iter(
+                    ctx,
+                    // Prune argument at index (idx_of_va_list_arg)
+                    signature.argument_types().iter().enumerate().filter_map(
+                        |(idx, t)| {
+                            if idx == *idx_of_va_list_arg {
+                                None
+                            } else {
+                                Some(t)
+                            }
+                        },
+                    ),
+                    // and replace it by a `...` (variadic symbol and the end of the signature)
+                    true,
+                ),
+            )
+        } else {
+            (&canonical_name, utils::fnsig_arguments(ctx, signature))
+        };
+        let ret = utils::fnsig_return_ty(ctx, signature);
+
+        let ident = ctx.rust_ident(ident);
         let tokens = quote! {
             #wasm_link_attribute
             extern #abi {
@@ -4349,6 +4421,13 @@ impl CodeGenerator for Function {
             }
         };
 
+        // Add the item to the serialization list if necessary
+        if should_wrap {
+            result
+                .items_to_serialize
+                .push((item.id(), wrap_as_variadic));
+        }
+
         // If we're doing dynamic binding generation, add to the dynamic items.
         if is_dynamic_function {
             let args_identifiers =
@@ -4851,9 +4930,9 @@ pub(crate) mod utils {
 
         writeln!(code, "// Static wrappers\n")?;
 
-        for &id in &result.items_to_serialize {
-            let item = context.resolve_item(id);
-            item.serialize(context, (), &mut vec![], &mut code)?;
+        for (id, wrap_as_variadic) in &result.items_to_serialize {
+            let item = context.resolve_item(*id);
+            item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?;
         }
 
         std::fs::write(source_path, code)?;
@@ -4861,6 +4940,62 @@ pub(crate) mod utils {
         Ok(())
     }
 
+    pub(super) fn wrap_as_variadic_fn(
+        ctx: &BindgenContext,
+        signature: &FunctionSig,
+        name: &str,
+    ) -> Option<super::WrapAsVariadic> {
+        // Fast path, exclude because:
+        //  - with 0 args: no va_list possible, so no point searching for one
+        //  - with 1 args: cannot have a `va_list` and another arg (required by va_start)
+        if signature.argument_types().len() <= 1 {
+            return None;
+        }
+
+        let mut it = signature.argument_types().iter().enumerate().filter_map(
+            |(idx, (_name, mut type_id))| {
+                // Hand rolled visitor that checks for the presence of `va_list`
+                loop {
+                    let ty = ctx.resolve_type(type_id);
+                    if Some("__builtin_va_list") == ty.name() {
+                        return Some(idx);
+                    }
+                    match ty.kind() {
+                        TypeKind::Alias(type_id_alias) => {
+                            type_id = *type_id_alias
+                        }
+                        TypeKind::ResolvedTypeRef(type_id_typedef) => {
+                            type_id = *type_id_typedef
+                        }
+                        _ => break,
+                    }
+                }
+                None
+            },
+        );
+
+        // Return THE idx (by checking that there is no idx after)
+        // This is done since we cannot handle multiple `va_list`
+        it.next().filter(|_| it.next().is_none()).and_then(|idx| {
+            // Call the `wrap_as_variadic_fn` callback
+            #[cfg(feature = "experimental")]
+            {
+                ctx.options()
+                    .last_callback(|c| c.wrap_as_variadic_fn(name))
+                    .map(|new_name| super::WrapAsVariadic {
+                        new_name,
+                        idx_of_va_list_arg: idx,
+                    })
+            }
+            #[cfg(not(feature = "experimental"))]
+            {
+                let _ = name;
+                let _ = idx;
+                None
+            }
+        })
+    }
+
     pub(crate) fn prepend_bitfield_unit_type(
         ctx: &BindgenContext,
         result: &mut Vec<proc_macro2::TokenStream>,
@@ -5225,16 +5360,18 @@ pub(crate) mod utils {
         fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true)
     }
 
-    pub(crate) fn fnsig_arguments(
+    pub(crate) fn fnsig_arguments_iter<
+        'a,
+        I: Iterator<Item = &'a (Option<String>, crate::ir::context::TypeId)>,
+    >(
         ctx: &BindgenContext,
-        sig: &FunctionSig,
+        args_iter: I,
+        is_variadic: bool,
     ) -> Vec<proc_macro2::TokenStream> {
         use super::ToPtr;
 
         let mut unnamed_arguments = 0;
-        let mut args = sig
-            .argument_types()
-            .iter()
+        let mut args = args_iter
             .map(|&(ref name, ty)| {
                 let arg_item = ctx.resolve_item(ty);
                 let arg_ty = arg_item.kind().expect_type();
@@ -5291,13 +5428,24 @@ pub(crate) mod utils {
             })
             .collect::<Vec<_>>();
 
-        if sig.is_variadic() {
+        if is_variadic {
             args.push(quote! { ... })
         }
 
         args
     }
 
+    pub(crate) fn fnsig_arguments(
+        ctx: &BindgenContext,
+        sig: &FunctionSig,
+    ) -> Vec<proc_macro2::TokenStream> {
+        fnsig_arguments_iter(
+            ctx,
+            sig.argument_types().iter(),
+            sig.is_variadic(),
+        )
+    }
+
     pub(crate) fn fnsig_argument_identifiers(
         ctx: &BindgenContext,
         sig: &FunctionSig,
diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs
index 1136234e..58e0882f 100644
--- a/bindgen/codegen/serialize.rs
+++ b/bindgen/codegen/serialize.rs
@@ -10,7 +10,7 @@ use crate::ir::item::ItemCanonicalName;
 use crate::ir::item_kind::ItemKind;
 use crate::ir::ty::{FloatKind, Type, TypeKind};
 
-use super::CodegenError;
+use super::{CodegenError, WrapAsVariadic};
 
 fn get_loc(item: &Item) -> String {
     item.location()
@@ -18,7 +18,7 @@ fn get_loc(item: &Item) -> String {
         .unwrap_or_else(|| "unknown".to_owned())
 }
 
-pub(crate) trait CSerialize<'a> {
+pub(super) trait CSerialize<'a> {
     type Extra;
 
     fn serialize<W: Write>(
@@ -31,18 +31,18 @@ pub(crate) trait CSerialize<'a> {
 }
 
 impl<'a> CSerialize<'a> for Item {
-    type Extra = ();
+    type Extra = &'a Option<WrapAsVariadic>;
 
     fn serialize<W: Write>(
         &self,
         ctx: &BindgenContext,
-        (): Self::Extra,
+        extra: Self::Extra,
         stack: &mut Vec<String>,
         writer: &mut W,
     ) -> Result<(), CodegenError> {
         match self.kind() {
             ItemKind::Function(func) => {
-                func.serialize(ctx, self, stack, writer)
+                func.serialize(ctx, (self, extra), stack, writer)
             }
             kind => Err(CodegenError::Serialize {
                 msg: format!("Cannot serialize item kind {:?}", kind),
@@ -53,12 +53,12 @@ impl<'a> CSerialize<'a> for Item {
 }
 
 impl<'a> CSerialize<'a> for Function {
-    type Extra = &'a Item;
+    type Extra = (&'a Item, &'a Option<WrapAsVariadic>);
 
     fn serialize<W: Write>(
         &self,
         ctx: &BindgenContext,
-        item: Self::Extra,
+        (item, wrap_as_variadic): Self::Extra,
         stack: &mut Vec<String>,
         writer: &mut W,
     ) -> Result<(), CodegenError> {
@@ -85,19 +85,30 @@ impl<'a> CSerialize<'a> for Function {
         let args = {
             let mut count = 0;
 
+            let idx_to_prune = wrap_as_variadic.as_ref().map(
+                |WrapAsVariadic {
+                     idx_of_va_list_arg, ..
+                 }| *idx_of_va_list_arg,
+            );
+
             signature
                 .argument_types()
                 .iter()
                 .cloned()
-                .map(|(opt_name, type_id)| {
-                    (
-                        opt_name.unwrap_or_else(|| {
-                            let name = format!("arg_{}", count);
-                            count += 1;
-                            name
-                        }),
-                        type_id,
-                    )
+                .enumerate()
+                .filter_map(|(idx, (opt_name, type_id))| {
+                    if Some(idx) == idx_to_prune {
+                        None
+                    } else {
+                        Some((
+                            opt_name.unwrap_or_else(|| {
+                                let name = format!("arg_{}", count);
+                                count += 1;
+                                name
+                            }),
+                            type_id,
+                        ))
+                    }
                 })
                 .collect::<Vec<_>>()
         };
@@ -106,33 +117,82 @@ impl<'a> CSerialize<'a> for Function {
         let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix());
 
         // The function's return type
-        let ret_ty = {
+        let (ret_item, ret_ty) = {
             let type_id = signature.return_type();
-            let item = ctx.resolve_item(type_id);
-            let ret_ty = item.expect_type();
+            let ret_item = ctx.resolve_item(type_id);
+            let ret_ty = ret_item.expect_type();
 
             // Write `ret_ty`.
-            ret_ty.serialize(ctx, item, stack, writer)?;
+            ret_ty.serialize(ctx, ret_item, stack, writer)?;
 
-            ret_ty
+            (ret_item, ret_ty)
         };
 
+        const INDENT: &str = "    ";
+
         // Write `wrap_name(args`.
         write!(writer, " {}(", wrap_name)?;
         serialize_args(&args, ctx, writer)?;
 
-        // Write `) { name(` if the function returns void and `) { return name(` if it does not.
-        if ret_ty.is_void() {
-            write!(writer, ") {{ {}(", name)?;
+        if wrap_as_variadic.is_none() {
+            // Write `) { name(` if the function returns void and `) { return name(` if it does not.
+            if ret_ty.is_void() {
+                write!(writer, ") {{ {}(", name)?;
+            } else {
+                write!(writer, ") {{ return {}(", name)?;
+            }
         } else {
-            write!(writer, ") {{ return {}(", name)?;
+            // Write `, ...) {`
+            writeln!(writer, ", ...) {{")?;
+
+            // Declare the return type `RET_TY ret;` if their is a need to do so
+            if !ret_ty.is_void() {
+                write!(writer, "{INDENT}")?;
+                ret_ty.serialize(ctx, ret_item, stack, writer)?;
+                writeln!(writer, " ret;")?;
+            }
+
+            // Setup va_list
+            writeln!(writer, "{INDENT}va_list ap;\n")?;
+            writeln!(
+                writer,
+                "{INDENT}va_start(ap, {});",
+                args.last().unwrap().0
+            )?;
+
+            write!(writer, "{INDENT}")?;
+            // Write `ret = name(` or `name(` depending if the function returns something
+            if !ret_ty.is_void() {
+                write!(writer, "ret = ")?;
+            }
+            write!(writer, "{}(", name)?;
         }
 
-        // Write `arg_names); }`.
-        serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| {
+        // Get the arguments names and insert at the right place if necessary `ap`
+        let mut args: Vec<_> = args.into_iter().map(|(name, _)| name).collect();
+        if let Some(WrapAsVariadic {
+            idx_of_va_list_arg, ..
+        }) = wrap_as_variadic
+        {
+            args.insert(*idx_of_va_list_arg, "ap".to_owned());
+        }
+
+        // Write `arg_names);`.
+        serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| {
             write!(buf, "{}", name).map_err(From::from)
         })?;
-        writeln!(writer, "); }}")?;
+        #[rustfmt::skip]
+        write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?;
+
+        if wrap_as_variadic.is_some() {
+            // End va_list and return the result if their is one
+            writeln!(writer, "{INDENT}va_end(ap);")?;
+            if !ret_ty.is_void() {
+                writeln!(writer, "{INDENT}return ret;")?;
+            }
+        }
+
+        writeln!(writer, "}}")?;
 
         Ok(())
     }
diff --git a/bindgen/codegen/struct_layout.rs b/bindgen/codegen/struct_layout.rs
index cca4a59b..56730603 100644
--- a/bindgen/codegen/struct_layout.rs
+++ b/bindgen/codegen/struct_layout.rs
@@ -6,6 +6,7 @@ use crate::ir::comp::CompInfo;
 use crate::ir::context::BindgenContext;
 use crate::ir::layout::Layout;
 use crate::ir::ty::{Type, TypeKind};
+use crate::FieldVisibilityKind;
 use proc_macro2::{self, Ident, Span};
 use std::cmp;
 
@@ -26,6 +27,7 @@ pub(crate) struct StructLayoutTracker<'a> {
     latest_field_layout: Option<Layout>,
     max_field_align: usize,
     last_field_was_bitfield: bool,
+    visibility: FieldVisibilityKind,
 }
 
 /// Returns a size aligned to a given value.
@@ -88,6 +90,7 @@ impl<'a> StructLayoutTracker<'a> {
         comp: &'a CompInfo,
         ty: &'a Type,
         name: &'a str,
+        visibility: FieldVisibilityKind,
     ) -> Self {
         let known_type_layout = ty.layout(ctx);
         let is_packed = comp.is_packed(ctx, known_type_layout.as_ref());
@@ -97,6 +100,7 @@ impl<'a> StructLayoutTracker<'a> {
             name,
             ctx,
             comp,
+            visibility,
             is_packed,
             known_type_layout,
             is_rust_union,
@@ -397,8 +401,10 @@ impl<'a> StructLayoutTracker<'a> {
 
         self.max_field_align = cmp::max(self.max_field_align, layout.align);
 
+        let vis = super::access_specifier(self.visibility);
+
         quote! {
-            pub #padding_field_name : #ty ,
+            #vis #padding_field_name : #ty ,
         }
     }
 
diff --git a/bindgen/deps.rs b/bindgen/deps.rs
index 2edeaa88..e348fa13 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<String>) -> 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>) -> String {
diff --git a/bindgen/ir/annotations.rs b/bindgen/ir/annotations.rs
index 423f6c4b..d085f5c5 100644
--- a/bindgen/ir/annotations.rs
+++ b/bindgen/ir/annotations.rs
@@ -9,7 +9,7 @@ use std::str::FromStr;
 use crate::clang;
 
 /// What kind of visibility modifer should be used for a struct or field?
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
 pub enum FieldVisibilityKind {
     /// Fields are marked as private, i.e., struct Foo {bar: bool}
     Private,
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index ee076254..bc9e59c3 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<Vec<u8>, 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<String, (String, usize)>,
+
     /// A set of all the included filenames.
     deps: BTreeSet<String>,
 
@@ -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 f4dce45d..1b9d7694 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 f25ef40f..5ec55e90 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 e4b71b04..9d1ebb45 100644
--- a/bindgen/lib.rs
+++ b/bindgen/lib.rs
@@ -172,6 +172,7 @@ pub enum Formatter {
     None,
     /// Use `rustfmt` to format the bindings.
     Rustfmt,
+    #[cfg(feature = "prettyplease")]
     /// Use `prettyplease` to format the bindings.
     Prettyplease,
 }
@@ -189,6 +190,7 @@ impl FromStr for Formatter {
         match s {
             "none" => Ok(Self::None),
             "rustfmt" => Ok(Self::Rustfmt),
+            #[cfg(feature = "prettyplease")]
             "prettyplease" => Ok(Self::Prettyplease),
             _ => Err(format!("`{}` is not a valid formatter", s)),
         }
@@ -200,6 +202,7 @@ impl std::fmt::Display for Formatter {
         let s = match self {
             Self::None => "none",
             Self::Rustfmt => "rustfmt",
+            #[cfg(feature = "prettyplease")]
             Self::Prettyplease => "prettyplease",
         };
 
@@ -683,6 +686,15 @@ fn rust_to_clang_target(rust_target: &str) -> String {
                 clang_target.strip_prefix("riscv32imc-").unwrap();
         }
         return clang_target;
+    } else if rust_target.starts_with("riscv32imc-") {
+        let mut clang_target = "riscv32-".to_owned();
+        clang_target.push_str(rust_target.strip_prefix("riscv32imc-").unwrap());
+        return clang_target;
+    } else if rust_target.starts_with("riscv32imac-") {
+        let mut clang_target = "riscv32-".to_owned();
+        clang_target
+            .push_str(rust_target.strip_prefix("riscv32imac-").unwrap());
+        return clang_target;
     }
     rust_target.to_owned()
 }
@@ -964,6 +976,7 @@ impl Bindings {
 
         match self.options.formatter {
             Formatter::None => return Ok(tokens.to_string()),
+            #[cfg(feature = "prettyplease")]
             Formatter::Prettyplease => {
                 return Ok(prettyplease::unparse(&syn::parse_quote!(#tokens)));
             }
@@ -1081,7 +1094,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
@@ -1122,8 +1136,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!(
@@ -1280,7 +1294,15 @@ fn test_rust_to_clang_target_riscv() {
     assert_eq!(
         rust_to_clang_target("riscv64gc-unknown-linux-gnu"),
         "riscv64-unknown-linux-gnu"
-    )
+    );
+    assert_eq!(
+        rust_to_clang_target("riscv32imc-unknown-none-elf"),
+        "riscv32-unknown-none-elf"
+    );
+    assert_eq!(
+        rust_to_clang_target("riscv32imac-unknown-none-elf"),
+        "riscv32-unknown-none-elf"
+    );
 }
 
 #[test]
diff --git a/book/book.toml b/book/book.toml
index 340134a3..78809c21 100644
--- a/book/book.toml
+++ b/book/book.toml
@@ -1,4 +1,8 @@
 [book]
-title = "The `bindgen` User Guide"
+title = "The bindgen User Guide"
 author = "The Servo project developers"
 description = "`bindgen` automatically generates Rust FFI bindings to C and C++ libraries."
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust-bindgen"
+edit-url-template = "https://github.com/rust-lang/rust-bindgen/edit/main/book/{path}"
diff --git a/book/src/non-system-libraries.md b/book/src/non-system-libraries.md
index c724a2fc..7d6e4e3d 100644
--- a/book/src/non-system-libraries.md
+++ b/book/src/non-system-libraries.md
@@ -1,17 +1,18 @@
 Now let's suppose we want to generate bindings for a non-system library. We
 will be the same crate setup as the previous tutorial. First let's create a new
-directory `hello` with two files inside it. A `c` source file `hello.c`
+directory `hello` with two files inside it. A C source file `hello.c`
 containing
 ```c
 int hello() {
     return 42;
 }
 ```
-and a `c` header file `hello.h` containing
+and a C header file `hello.h` containing
 ```c
 int hello();
 ```
-given that the library has not been compiled yet, we need to modify the
+
+Given that the library has not been compiled yet, we need to modify the
 `build.rs` build script to compile the `hello.c` source file into a static
 libary:
 
@@ -103,4 +104,3 @@ fn main() {
         .expect("Couldn't write bindings!");
 }
 ```
-
diff --git a/book/src/tutorial-1.md b/book/src/tutorial-1.md
index 182a777f..464b6b9d 100644
--- a/book/src/tutorial-1.md
+++ b/book/src/tutorial-1.md
@@ -3,15 +3,14 @@
 First we need to declare a build-time dependency on `bindgen` by adding it to
 the `[build-dependencies]` section of our crate's `Cargo.toml` file.
 
-Please always use the latest version of `bindgen`, it has the most fixes and
-best compatibility. At the time of writing the latest bindgen is `0.53.1`, but
-you can always check [the bindgen page of
-crates.io](https://crates.io/crates/bindgen) to verify the latest version if
-you're unsure.
+Please always use the latest version of `bindgen`, as it has the most fixes and
+best compatibility.
+You can always check the latest version at
+[the bindgen page in crates.io](https://crates.io/crates/bindgen).
 
 ```toml
 [build-dependencies]
-bindgen = "0.53.1"
+bindgen = "0.65.1"
 ```
 
 > ⚠️ **Warning**
diff --git a/book/src/tutorial-3.md b/book/src/tutorial-3.md
index dcd67c5c..599ece27 100644
--- a/book/src/tutorial-3.md
+++ b/book/src/tutorial-3.md
@@ -10,8 +10,6 @@ like `./target/debug/build/bindgen-tutorial-bzip2-sys-afc7747d7eafd720/out/`.
 Note that the associated shared object to `bz2` is `libbz2.so`. In general, a `lib<name>.so` should be referenced in the build file by `<name>`.
 
 ```rust,ignore
-extern crate bindgen;
-
 use std::env;
 use std::path::PathBuf;
 
@@ -52,6 +50,6 @@ fn main() {
 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]
+[There's more info about `build.rs` files in the Cargo documentation.][build-rs]
 
-[build-rs]: http://doc.crates.io/build-script.html
+[build-rs]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
diff --git a/ci/no-includes.sh b/ci/no-includes.sh
index 97966cb0..32c20059 100755
--- a/ci/no-includes.sh
+++ b/ci/no-includes.sh
@@ -1,13 +1,17 @@
 #!/usr/bin/env bash
 
 # Don't allow any system include directives in tests.
+# 
+# We make an exception for stdarg.h which is used for
+# the wrapped va_list feature. stdarg.h is available since C89
+# therefor not having this header is a sign of a bigger issue.
 
 set -eu
 cd "$(dirname "$0")/.."
 
 echo "Checking for #include directives of system headers..."
 
-grep -rn '#include\s*<.*>' bindgen-tests/tests/headers || {
+grep -rn '#include\s*<(?!stdarg).*>' bindgen-tests/tests/headers || {
     echo "Found none; OK!"
     exit 0
 }


Test patch:
diff --git a/bindgen-tests/Cargo.toml b/bindgen-tests/Cargo.toml
index ab53660a..eb7e1b17 100644
--- a/bindgen-tests/Cargo.toml
+++ b/bindgen-tests/Cargo.toml
@@ -6,10 +6,10 @@ publish = false
 
 [dev-dependencies]
 bindgen = { path = "../bindgen", features = ["__cli", "experimental"] }
-diff = "0.1"
-shlex = "1"
 clap = { version = "4", features = ["derive"] }
 clap_complete = "4"
+diff = "0.1"
+shlex = "1"
 prettyplease = { version = "0.2.0" }
 syn = { version = "2.0" }
 tempfile = "3"
diff --git a/bindgen-tests/tests/expectations/Cargo.toml b/bindgen-tests/tests/expectations/Cargo.toml
index 086d0e8c..bf7da253 100644
--- a/bindgen-tests/tests/expectations/Cargo.toml
+++ b/bindgen-tests/tests/expectations/Cargo.toml
@@ -10,6 +10,6 @@ authors = [
 edition = "2018"
 
 [dependencies]
-objc = "0.2"
 block = "0.1"
 libloading = "0.7"
+objc = "0.2"
diff --git a/bindgen-tests/tests/expectations/tests/allowlist-file.rs b/bindgen-tests/tests/expectations/tests/allowlist-file.rs
index 1ee7a192..63953ccb 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/default_visibility_private_respects_cxx_access_spec.rs b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
index d38790f3..453a3054 100644
--- a/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
+++ b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
@@ -93,7 +93,7 @@ pub struct Point {
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Color {
     _bitfield_align_1: [u8; 0],
-    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
+    _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
 }
 impl Color {
     #[inline]
@@ -130,7 +130,7 @@ impl Color {
         }
     }
     #[inline]
-    pub fn new_bitfield_1(
+    fn new_bitfield_1(
         r: ::std::os::raw::c_char,
         g: ::std::os::raw::c_char,
         b: ::std::os::raw::c_char,
diff --git a/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs b/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs
new file mode 100644
index 00000000..9411ccc7
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/field-visibility-callback.rs
@@ -0,0 +1,166 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct __BindgenBitfieldUnit<Storage> {
+    storage: Storage,
+}
+impl<Storage> __BindgenBitfieldUnit<Storage> {
+    #[inline]
+    pub const fn new(storage: Storage) -> Self {
+        Self { storage }
+    }
+}
+impl<Storage> __BindgenBitfieldUnit<Storage>
+where
+    Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+    #[inline]
+    pub fn get_bit(&self, index: usize) -> bool {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = self.storage.as_ref()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") {
+            7 - (index % 8)
+        } else {
+            index % 8
+        };
+        let mask = 1 << bit_index;
+        byte & mask == mask
+    }
+    #[inline]
+    pub fn set_bit(&mut self, index: usize, val: bool) {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = &mut self.storage.as_mut()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") {
+            7 - (index % 8)
+        } else {
+            index % 8
+        };
+        let mask = 1 << bit_index;
+        if val {
+            *byte |= mask;
+        } else {
+            *byte &= !mask;
+        }
+    }
+    #[inline]
+    pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!(
+            (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()
+        );
+        let mut val = 0;
+        for i in 0..(bit_width as usize) {
+            if self.get_bit(i + bit_offset) {
+                let index = if cfg!(target_endian = "big") {
+                    bit_width as usize - 1 - i
+                } else {
+                    i
+                };
+                val |= 1 << index;
+            }
+        }
+        val
+    }
+    #[inline]
+    pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!(
+            (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()
+        );
+        for i in 0..(bit_width as usize) {
+            let mask = 1 << i;
+            let val_bit_is_set = val & mask == mask;
+            let index = if cfg!(target_endian = "big") {
+                bit_width as usize - 1 - i
+            } else {
+                i
+            };
+            self.set_bit(index + bit_offset, val_bit_is_set);
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct my_struct {
+    pub a: ::std::os::raw::c_int,
+    private_b: ::std::os::raw::c_int,
+    _bitfield_align_1: [u8; 0],
+    _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
+    __bindgen_padding_0: [u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_my_struct() {
+    const UNINIT: ::std::mem::MaybeUninit<my_struct> = ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of:: < my_struct > (), 12usize, concat!("Size of: ",
+        stringify!(my_struct))
+    );
+    assert_eq!(
+        ::std::mem::align_of:: < my_struct > (), 4usize, concat!("Alignment of ",
+        stringify!(my_struct))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((* ptr).a) as usize - ptr as usize }, 0usize,
+        concat!("Offset of field: ", stringify!(my_struct), "::", stringify!(a))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((* ptr).private_b) as usize - ptr as usize },
+        4usize, concat!("Offset of field: ", stringify!(my_struct), "::",
+        stringify!(private_b))
+    );
+}
+impl my_struct {
+    #[inline]
+    pub fn c(&self) -> ::std::os::raw::c_int {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) }
+    }
+    #[inline]
+    pub fn set_c(&mut self, val: ::std::os::raw::c_int) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    fn private_d(&self) -> ::std::os::raw::c_int {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u32) }
+    }
+    #[inline]
+    fn set_private_d(&mut self, val: ::std::os::raw::c_int) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(1usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    fn new_bitfield_1(
+        c: ::std::os::raw::c_int,
+        private_d: ::std::os::raw::c_int,
+    ) -> __BindgenBitfieldUnit<[u8; 1usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                1u8,
+                {
+                    let c: u32 = unsafe { ::std::mem::transmute(c) };
+                    c as u64
+                },
+            );
+        __bindgen_bitfield_unit
+            .set(
+                1usize,
+                1u8,
+                {
+                    let private_d: u32 = unsafe { ::std::mem::transmute(private_d) };
+                    private_d as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
diff --git a/bindgen-tests/tests/expectations/tests/field-visibility.rs b/bindgen-tests/tests/expectations/tests/field-visibility.rs
new file mode 100644
index 00000000..b4e06208
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/field-visibility.rs
@@ -0,0 +1,179 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct __BindgenBitfieldUnit<Storage> {
+    storage: Storage,
+}
+impl<Storage> __BindgenBitfieldUnit<Storage> {
+    #[inline]
+    pub const fn new(storage: Storage) -> Self {
+        Self { storage }
+    }
+}
+impl<Storage> __BindgenBitfieldUnit<Storage>
+where
+    Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+    #[inline]
+    pub fn get_bit(&self, index: usize) -> bool {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = self.storage.as_ref()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") {
+            7 - (index % 8)
+        } else {
+            index % 8
+        };
+        let mask = 1 << bit_index;
+        byte & mask == mask
+    }
+    #[inline]
+    pub fn set_bit(&mut self, index: usize, val: bool) {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = &mut self.storage.as_mut()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") {
+            7 - (index % 8)
+        } else {
+            index % 8
+        };
+        let mask = 1 << bit_index;
+        if val {
+            *byte |= mask;
+        } else {
+            *byte &= !mask;
+        }
+    }
+    #[inline]
+    pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!(
+            (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()
+        );
+        let mut val = 0;
+        for i in 0..(bit_width as usize) {
+            if self.get_bit(i + bit_offset) {
+                let index = if cfg!(target_endian = "big") {
+                    bit_width as usize - 1 - i
+                } else {
+                    i
+                };
+                val |= 1 << index;
+            }
+        }
+        val
+    }
+    #[inline]
+    pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!(
+            (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()
+        );
+        for i in 0..(bit_width as usize) {
+            let mask = 1 << i;
+            let val_bit_is_set = val & mask == mask;
+            let index = if cfg!(target_endian = "big") {
+                bit_width as usize - 1 - i
+            } else {
+                i
+            };
+            self.set_bit(index + bit_offset, val_bit_is_set);
+        }
+    }
+}
+#[repr(C)]
+#[repr(align(4))]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct my_struct1 {
+    _bitfield_align_1: [u8; 0],
+    _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
+    __bindgen_padding_0: [u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_my_struct1() {
+    assert_eq!(
+        ::std::mem::size_of:: < my_struct1 > (), 4usize, concat!("Size of: ",
+        stringify!(my_struct1))
+    );
+    assert_eq!(
+        ::std::mem::align_of:: < my_struct1 > (), 4usize, concat!("Alignment of ",
+        stringify!(my_struct1))
+    );
+}
+impl my_struct1 {
+    #[inline]
+    fn a(&self) -> ::std::os::raw::c_int {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) }
+    }
+    #[inline]
+    fn set_a(&mut self, val: ::std::os::raw::c_int) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    fn new_bitfield_1(a: ::std::os::raw::c_int) -> __BindgenBitfieldUnit<[u8; 1usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                1u8,
+                {
+                    let a: u32 = unsafe { ::std::mem::transmute(a) };
+                    a as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
+#[repr(C)]
+#[repr(align(4))]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct my_struct2 {
+    pub _bitfield_align_1: [u8; 0],
+    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
+    pub __bindgen_padding_0: [u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_my_struct2() {
+    assert_eq!(
+        ::std::mem::size_of:: < my_struct2 > (), 4usize, concat!("Size of: ",
+        stringify!(my_struct2))
+    );
+    assert_eq!(
+        ::std::mem::align_of:: < my_struct2 > (), 4usize, concat!("Alignment of ",
+        stringify!(my_struct2))
+    );
+}
+impl my_struct2 {
+    #[inline]
+    pub fn a(&self) -> ::std::os::raw::c_int {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) }
+    }
+    #[inline]
+    pub fn set_a(&mut self, val: ::std::os::raw::c_int) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn new_bitfield_1(
+        a: ::std::os::raw::c_int,
+    ) -> __BindgenBitfieldUnit<[u8; 1usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                1u8,
+                {
+                    let a: u32 = unsafe { ::std::mem::transmute(a) };
+                    a as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
diff --git a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c
index 8d6e97aa..cf1106ec 100644
--- a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c
+++ b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c
@@ -11,3 +11,21 @@ int takes_alias__extern(func f) { return takes_alias(f); }
 int takes_qualified__extern(const int *const *arg) { return takes_qualified(arg); }
 enum foo takes_enum__extern(const enum foo f) { return takes_enum(f); }
 void nevermore__extern(void) { nevermore(); }
+void no_extra_argument__extern(__builtin_va_list va) { no_extra_argument(va); }
+int many_va_list__extern(int i, __builtin_va_list va1, __builtin_va_list va2) { return many_va_list(i, va1, va2); }
+int wrap_as_variadic_fn1__extern(int i, ...) {
+    int ret;
+    va_list ap;
+
+    va_start(ap, i);
+    ret = wrap_as_variadic_fn1(i, ap);
+    va_end(ap);
+    return ret;
+}
+void wrap_as_variadic_fn2__extern(int i, ...) {
+    va_list ap;
+
+    va_start(ap, i);
+    wrap_as_variadic_fn2(i, ap);
+    va_end(ap);
+}
diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs
index cfbf2f61..4ec58e78 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 b97bbac9..fa55d5c1 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<T> ::std::cmp::PartialEq for __BindgenUnionField<T> {
 }
 impl<T> ::std::cmp::Eq for __BindgenUnionField<T> {}
 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 1ee04559..ee6bdf01 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 d9171be2..3654c62c 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 1ec0744f..0916a16b 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 086384c4..c20732c6 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 83543b85..a99711b2 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<T> {
-        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/private_fields.rs b/bindgen-tests/tests/expectations/tests/private_fields.rs
index 3408a9a3..120ed858 100644
--- a/bindgen-tests/tests/expectations/tests/private_fields.rs
+++ b/bindgen-tests/tests/expectations/tests/private_fields.rs
@@ -483,3 +483,113 @@ impl Default for WithAnonUnion {
         }
     }
 }
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Override {
+    pub a: ::std::os::raw::c_uint,
+    /// <div rustbindgen private></div>
+    b: ::std::os::raw::c_uint,
+    private_c: ::std::os::raw::c_uint,
+    pub _bitfield_align_1: [u8; 0],
+    _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>,
+    pub __bindgen_padding_0: u16,
+}
+#[test]
+fn bindgen_test_layout_Override() {
+    const UNINIT: ::std::mem::MaybeUninit<Override> = ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of:: < Override > (), 16usize, concat!("Size of: ",
+        stringify!(Override))
+    );
+    assert_eq!(
+        ::std::mem::align_of:: < Override > (), 4usize, concat!("Alignment of ",
+        stringify!(Override))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((* ptr).a) as usize - ptr as usize }, 0usize,
+        concat!("Offset of field: ", stringify!(Override), "::", stringify!(a))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((* ptr).b) as usize - ptr as usize }, 4usize,
+        concat!("Offset of field: ", stringify!(Override), "::", stringify!(b))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((* ptr).private_c) as usize - ptr as usize },
+        8usize, concat!("Offset of field: ", stringify!(Override), "::",
+        stringify!(private_c))
+    );
+}
+impl Override {
+    #[inline]
+    pub fn bf_a(&self) -> ::std::os::raw::c_uint {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u32) }
+    }
+    #[inline]
+    pub fn set_bf_a(&mut self, val: ::std::os::raw::c_uint) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 4u8, val as u64)
+        }
+    }
+    #[inline]
+    fn bf_b(&self) -> ::std::os::raw::c_uint {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u32) }
+    }
+    #[inline]
+    fn set_bf_b(&mut self, val: ::std::os::raw::c_uint) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(4usize, 4u8, val as u64)
+        }
+    }
+    #[inline]
+    fn private_bf_c(&self) -> ::std::os::raw::c_uint {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 4u8) as u32) }
+    }
+    #[inline]
+    fn set_private_bf_c(&mut self, val: ::std::os::raw::c_uint) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(8usize, 4u8, val as u64)
+        }
+    }
+    #[inline]
+    fn new_bitfield_1(
+        bf_a: ::std::os::raw::c_uint,
+        bf_b: ::std::os::raw::c_uint,
+        private_bf_c: ::std::os::raw::c_uint,
+    ) -> __BindgenBitfieldUnit<[u8; 2usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                4u8,
+                {
+                    let bf_a: u32 = unsafe { ::std::mem::transmute(bf_a) };
+                    bf_a as u64
+                },
+            );
+        __bindgen_bitfield_unit
+            .set(
+                4usize,
+                4u8,
+                {
+                    let bf_b: u32 = unsafe { ::std::mem::transmute(bf_b) };
+                    bf_b as u64
+                },
+            );
+        __bindgen_bitfield_unit
+            .set(
+                8usize,
+                4u8,
+                {
+                    let private_bf_c: u32 = unsafe {
+                        ::std::mem::transmute(private_bf_c)
+                    };
+                    private_bf_c as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
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 ab87b416..5816a6c5 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-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs
index 122f4c9c..03f3907e 100644
--- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs
+++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs
@@ -50,3 +50,36 @@ extern "C" {
     #[link_name = "nevermore__extern"]
     pub fn nevermore();
 }
+extern "C" {
+    #[link_name = "no_extra_argument__extern"]
+    pub fn no_extra_argument(va: *mut __va_list_tag);
+}
+extern "C" {
+    #[link_name = "many_va_list__extern"]
+    pub fn many_va_list(
+        i: ::std::os::raw::c_int,
+        va1: *mut __va_list_tag,
+        va2: *mut __va_list_tag,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    #[link_name = "wrap_as_variadic_fn1__extern"]
+    pub fn wrap_as_variadic_fn1_wrapped(
+        i: ::std::os::raw::c_int,
+        ...
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    #[link_name = "wrap_as_variadic_fn2__extern"]
+    pub fn wrap_as_variadic_fn2_wrapped(i: ::std::os::raw::c_int, ...);
+}
+pub type __builtin_va_list = [__va_list_tag; 1usize];
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __va_list_tag {
+    pub gp_offset: ::std::os::raw::c_uint,
+    pub fp_offset: ::std::os::raw::c_uint,
+    pub overflow_arg_area: *mut ::std::os::raw::c_void,
+    pub reg_save_area: *mut ::std::os::raw::c_void,
+    _unused: [u8; 0],
+}
diff --git a/bindgen-tests/tests/headers/field-visibility-callback.h b/bindgen-tests/tests/headers/field-visibility-callback.h
new file mode 100644
index 00000000..d2fe3ace
--- /dev/null
+++ b/bindgen-tests/tests/headers/field-visibility-callback.h
@@ -0,0 +1,9 @@
+// bindgen-flags: --default-visibility private
+// bindgen-parse-callbacks: field-visibility-default-private
+
+struct my_struct {
+    int a;
+    int private_b;
+    int c: 1;
+    int private_d: 1;
+};
diff --git a/bindgen-tests/tests/headers/field-visibility.h b/bindgen-tests/tests/headers/field-visibility.h
new file mode 100644
index 00000000..adb73159
--- /dev/null
+++ b/bindgen-tests/tests/headers/field-visibility.h
@@ -0,0 +1,10 @@
+// bindgen-flags: --default-visibility private --no-doc-comments
+
+struct my_struct1 {
+    int a: 1;
+};
+
+/** <div rustbindgen private="false"></div> */
+struct my_struct2 {
+    int a: 1;
+};
diff --git a/bindgen-tests/tests/headers/private_fields.hpp b/bindgen-tests/tests/headers/private_fields.hpp
index 9d55ebca..965acde9 100644
--- a/bindgen-tests/tests/headers/private_fields.hpp
+++ b/bindgen-tests/tests/headers/private_fields.hpp
@@ -1,4 +1,6 @@
 // bindgen-flags: --respect-cxx-access-specs
+// bindgen-parse-callbacks: field-visibility-default-public
+
 class PubPriv {
   public:
     int x;
@@ -41,4 +43,21 @@ class WithAnonStruct {
 
 class WithAnonUnion {
   union {};
-};
\ No newline at end of file
+};
+
+class Override {
+ public:
+  unsigned int a;
+  // override with annotation
+  /** <div rustbindgen private></div> */
+  unsigned int b;
+  // override with callback
+  unsigned int private_c;
+
+  unsigned int bf_a : 4;
+  // override with annotation
+  /** <div rustbindgen private></div> */
+  unsigned int bf_b : 4;
+  // override with callback
+  unsigned int private_bf_c : 4;
+};
diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h
index 85dfeac2..8dcabe7b 100644
--- a/bindgen-tests/tests/headers/wrap-static-fns.h
+++ b/bindgen-tests/tests/headers/wrap-static-fns.h
@@ -1,4 +1,11 @@
 // bindgen-flags: --experimental --wrap-static-fns
+// bindgen-parse-callbacks: wrap-as-variadic-fn
+
+// to avoid poluting theexpectation tests we put the stdarg.h behind a conditional
+// variable only used in bindgen-integration
+#ifdef USE_VA_HEADER
+#include <stdarg.h>
+#endif
 
 static inline int foo() {
     return 11;
@@ -48,3 +55,28 @@ static inline void nevermore() {
 static inline int variadic(int x, ...) {
     return x;
 }
+
+static inline void no_extra_argument(__builtin_va_list va) {}
+
+static inline int many_va_list(int i, __builtin_va_list va1, __builtin_va_list va2) {
+    return i;
+}
+
+#ifndef USE_VA_HEADER
+static inline int wrap_as_variadic_fn1(int i, __builtin_va_list va) {
+    return i;
+}
+
+static inline void wrap_as_variadic_fn2(int i, __builtin_va_list va) {}
+#else
+static inline int wrap_as_variadic_fn1(int i, va_list va) {
+    int res = 0;
+
+    for (int j = 0; j < i; j++)
+        res += (int) va_arg(va, int);
+
+    return res;
+}
+
+static inline void wrap_as_variadic_fn2(int i, va_list va) {}
+#endif
diff --git a/bindgen-tests/tests/parse_callbacks/mod.rs b/bindgen-tests/tests/parse_callbacks/mod.rs
index 85082b63..820432ba 100644
--- a/bindgen-tests/tests/parse_callbacks/mod.rs
+++ b/bindgen-tests/tests/parse_callbacks/mod.rs
@@ -1,4 +1,5 @@
 use bindgen::callbacks::*;
+use bindgen::FieldVisibilityKind;
 
 #[derive(Debug)]
 pub struct RemovePrefixParseCallback {
@@ -86,25 +87,75 @@ impl ParseCallbacks for BlocklistedTypeImplementsTrait {
     }
 }
 
+#[derive(Debug)]
+struct FieldVisibility {
+    default: FieldVisibilityKind,
+}
+
+/// Implements the `field_visibility` function of the trait by checking if the
+/// field name starts with `private_`. If it does it makes it private, if it
+/// doesn't it makes it public, taking into account the default visibility.
+impl ParseCallbacks for FieldVisibility {
+    fn field_visibility(
+        &self,
+        FieldInfo { field_name, .. }: FieldInfo,
+    ) -> Option<FieldVisibilityKind> {
+        match (self.default, field_name.starts_with("private_")) {
+            (FieldVisibilityKind::Private, false) => {
+                Some(FieldVisibilityKind::Public)
+            }
+            (FieldVisibilityKind::Public, true) => {
+                Some(FieldVisibilityKind::Private)
+            }
+            (FieldVisibilityKind::PublicCrate, _) => unimplemented!(),
+            _ => None,
+        }
+    }
+}
+
+#[derive(Debug)]
+pub(super) struct WrapAsVariadicFn;
+
+impl ParseCallbacks for WrapAsVariadicFn {
+    fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
+        Some(name.to_owned() + "_wrapped")
+    }
+}
+
 pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
+    fn try_strip_prefix<'a>(s: &'a str, prefix: &str) -> Option<&'a str> {
+        if s.starts_with(prefix) {
+            Some(&s[prefix.len()..])
+        } else {
+            None
+        }
+    }
+
     match cb {
         "enum-variant-rename" => Box::new(EnumVariantRename),
         "blocklisted-type-implements-trait" => {
             Box::new(BlocklistedTypeImplementsTrait)
         }
+        "wrap-as-variadic-fn" => Box::new(WrapAsVariadicFn),
         call_back => {
-            if call_back.starts_with("remove-function-prefix-") {
-                let prefix = call_back
-                    .split("remove-function-prefix-")
-                    .last()
-                    .to_owned();
-                let lnopc = RemovePrefixParseCallback::new(prefix.unwrap());
+            if let Some(prefix) =
+                try_strip_prefix(call_back, "remove-function-prefix-")
+            {
+                let lnopc = RemovePrefixParseCallback::new(prefix);
                 Box::new(lnopc)
-            } else if call_back.starts_with("prefix-link-name-") {
-                let prefix =
-                    call_back.split("prefix-link-name-").last().to_owned();
-                let plnpc = PrefixLinkNameParseCallback::new(prefix.unwrap());
+            } else if let Some(prefix) =
+                try_strip_prefix(call_back, "prefix-link-name-")
+            {
+                let plnpc = PrefixLinkNameParseCallback::new(prefix);
                 Box::new(plnpc)
+            } else if let Some(default) =
+                try_strip_prefix(call_back, "field-visibility-default-")
+            {
+                Box::new(FieldVisibility {
+                    default: default.parse().expect(
+                        "unable to parse field-visibility-default callback",
+                    ),
+                })
             } else {
                 panic!("Couldn't find name ParseCallbacks: {}", cb)
             }
diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs
index f83c1a7a..895e1cac 100644
--- a/bindgen-tests/tests/tests.rs
+++ b/bindgen-tests/tests/tests.rs
@@ -618,6 +618,7 @@ fn test_wrap_static_fns() {
         .header("tests/headers/wrap-static-fns.h")
         .wrap_static_fns(true)
         .wrap_static_fns_path(generated_path.display().to_string())
+        .parse_callbacks(Box::new(parse_callbacks::WrapAsVariadicFn))
         .generate()
         .expect("Failed to generate bindings");