Repository: rust-lang/rust-bindgen
Pull request #2795 (2024-03-28 07:43:25)

remove redundant import


Patch:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index f79ce103..1fbc1504 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,13 +1,16 @@
-# To trigger this:
-# - go to Actions > Publish
-# - click the Run Workflow dropdown in the top-right
-name: Publish
-on: workflow_dispatch
+# This is triggered after the Release workflow successfully completes its run
+on:
+  workflow_run:
+    workflows:
+      - Release
+    types:
+      - completed
 env:
   CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
 jobs:
   cargo-publish:
     runs-on: ubuntu-latest
+    if: ${{ github.event.workflow_run.conclusion == 'success' }}
     steps:
       - name: Checkout sources
         uses: actions/checkout@v3
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 67e91345..af069be2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -563,7 +563,7 @@ cargo release [patch|minor] --no-publish --execute
 This does the following:
 
 - Bump the version.
-- Turn the `Unreleased` section of the changelog into the section for the version being published.
+- Turn the `Unreleased` section of the changelog into the section for the version being released.
 - Update the table of contents of the changelog using `doctoc`.
 - Tag (`git tag`) the HEAD commit
 - Push (`git push`) to GitHub
@@ -573,6 +573,10 @@ The `patch` and `minor` refer to semver concepts:
 - `patch` would bump __v0.68.1__ to __v0.68.2__
 - `minor` would bump __v0.68.2__ to __v0.69.0__
 
+> NOTE:
+> We use the `--no-publish` so that the crates are only published after the release is complete.
+> This is automatic, provided the release CI job is successful.
+
 ### Create a new release on Github
 
 The release is automated with the help of `.github/workflows/release.yml`,
diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs
index 66bb3f14..815a28f4 100644
--- a/bindgen-cli/options.rs
+++ b/bindgen-cli/options.rs
@@ -400,6 +400,12 @@ struct BindgenCommand {
     /// Wrap unsafe operations in unsafe blocks.
     #[arg(long)]
     wrap_unsafe_ops: bool,
+    /// Enable fallback for clang macro parsing.
+    #[arg(long)]
+    clang_macro_fallback: bool,
+    /// Set path for temporary files generated by fallback for clang macro parsing.
+    #[arg(long)]
+    clang_macro_fallback_build_dir: Option<PathBuf>,
     /// Derive custom traits on any kind of type. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros.
     #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)]
     with_derive_custom: Vec<(Vec<String>, String)>,
@@ -554,6 +560,8 @@ where
         merge_extern_blocks,
         override_abi,
         wrap_unsafe_ops,
+        clang_macro_fallback,
+        clang_macro_fallback_build_dir,
         with_derive_custom,
         with_derive_custom_struct,
         with_derive_custom_enum,
@@ -1023,6 +1031,14 @@ where
         builder = builder.wrap_unsafe_ops(true);
     }
 
+    if clang_macro_fallback {
+        builder = builder.clang_macro_fallback();
+    }
+
+    if let Some(path) = clang_macro_fallback_build_dir {
+        builder = builder.clang_macro_fallback_build_dir(path);
+    }
+
     #[derive(Debug)]
     struct CustomDeriveCallback {
         derives: Vec<String>,
diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs
index 2a0763b0..6b06c91b 100644
--- a/bindgen-integration/build.rs
+++ b/bindgen-integration/build.rs
@@ -1,10 +1,9 @@
 extern crate bindgen;
-extern crate cc;
 
 use bindgen::callbacks::{
     DeriveInfo, IntKind, MacroParsingBehavior, ParseCallbacks,
 };
-use bindgen::{Builder, CargoCallbacks, EnumVariation, Formatter};
+use bindgen::{Builder, EnumVariation, Formatter};
 use std::collections::HashSet;
 use std::env;
 use std::path::PathBuf;
@@ -234,7 +233,9 @@ fn setup_wrap_static_fns_test() {
     // generate external bindings with the external .c and .h files
     let bindings = Builder::default()
         .header(input_header_file_path_str)
-        .parse_callbacks(Box::new(CargoCallbacks))
+        .parse_callbacks(Box::new(
+            bindgen::CargoCallbacks::new().rerun_on_header_files(true),
+        ))
         .parse_callbacks(Box::new(WrappedVaListCallback))
         .wrap_static_fns(true)
         .wrap_static_fns_path(
diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs
index e2344770..c37055ee 100755
--- a/bindgen-integration/src/lib.rs
+++ b/bindgen-integration/src/lib.rs
@@ -12,7 +12,6 @@ use std::ffi::CStr;
 use std::mem;
 use std::os::raw::c_int;
 
-#[allow(unused)]
 use bindings::testing::Bar; // This type is generated from module_raw_line.
 
 type MacroInteger = isize;
diff --git a/bindgen/clang.rs b/bindgen/clang.rs
index a9a0ec81..04465b6b 100644
--- a/bindgen/clang.rs
+++ b/bindgen/clang.rs
@@ -10,6 +10,7 @@ use std::cmp;
 
 use std::ffi::{CStr, CString};
 use std::fmt;
+use std::fs::OpenOptions;
 use std::hash::Hash;
 use std::hash::Hasher;
 use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
@@ -1868,6 +1869,27 @@ impl TranslationUnit {
         }
     }
 
+    /// Save a translation unit to the given file.
+    pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> {
+        let file = if let Ok(cstring) = CString::new(file) {
+            cstring
+        } else {
+            return Err(CXSaveError_Unknown);
+        };
+        let ret = unsafe {
+            clang_saveTranslationUnit(
+                self.x,
+                file.as_ptr(),
+                clang_defaultSaveOptions(self.x),
+            )
+        };
+        if ret != 0 {
+            Err(ret)
+        } else {
+            Ok(())
+        }
+    }
+
     /// Is this the null translation unit?
     pub(crate) fn is_null(&self) -> bool {
         self.x.is_null()
@@ -1882,6 +1904,89 @@ impl Drop for TranslationUnit {
     }
 }
 
+/// Translation unit used for macro fallback parsing
+pub(crate) struct FallbackTranslationUnit {
+    file_path: String,
+    pch_paths: Vec<String>,
+    idx: Box<Index>,
+    tu: TranslationUnit,
+}
+
+impl fmt::Debug for FallbackTranslationUnit {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "FallbackTranslationUnit {{ }}")
+    }
+}
+
+impl FallbackTranslationUnit {
+    /// Create a new fallback translation unit
+    pub(crate) fn new(
+        file: String,
+        pch_paths: Vec<String>,
+        c_args: &[Box<str>],
+    ) -> Option<Self> {
+        // Create empty file
+        OpenOptions::new()
+            .write(true)
+            .create(true)
+            .truncate(true)
+            .open(&file)
+            .ok()?;
+
+        let f_index = Box::new(Index::new(true, false));
+        let f_translation_unit = TranslationUnit::parse(
+            &f_index,
+            &file,
+            c_args,
+            &[],
+            CXTranslationUnit_None,
+        )?;
+        Some(FallbackTranslationUnit {
+            file_path: file,
+            pch_paths,
+            tu: f_translation_unit,
+            idx: f_index,
+        })
+    }
+
+    /// Get reference to underlying translation unit.
+    pub(crate) fn translation_unit(&self) -> &TranslationUnit {
+        &self.tu
+    }
+
+    /// Reparse a translation unit.
+    pub(crate) fn reparse(
+        &mut self,
+        unsaved_contents: &str,
+    ) -> Result<(), CXErrorCode> {
+        let unsaved = &[UnsavedFile::new(&self.file_path, unsaved_contents)];
+        let mut c_unsaved: Vec<CXUnsavedFile> =
+            unsaved.iter().map(|f| f.x).collect();
+        let ret = unsafe {
+            clang_reparseTranslationUnit(
+                self.tu.x,
+                unsaved.len() as c_uint,
+                c_unsaved.as_mut_ptr(),
+                clang_defaultReparseOptions(self.tu.x),
+            )
+        };
+        if ret != 0 {
+            Err(ret)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl Drop for FallbackTranslationUnit {
+    fn drop(&mut self) {
+        let _ = std::fs::remove_file(&self.file_path);
+        for pch in self.pch_paths.iter() {
+            let _ = std::fs::remove_file(pch);
+        }
+    }
+}
+
 /// A diagnostic message generated while parsing a translation unit.
 pub(crate) struct Diagnostic {
     x: CXDiagnostic,
diff --git a/bindgen/codegen/dyngen.rs b/bindgen/codegen/dyngen.rs
index c067fada..b26c0b18 100644
--- a/bindgen/codegen/dyngen.rs
+++ b/bindgen/codegen/dyngen.rs
@@ -90,8 +90,6 @@ impl DynamicItems {
         };
 
         quote! {
-            extern crate libloading;
-
             pub struct #lib_ident {
                 __library: ::libloading::Library,
                 #(#struct_members)*
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index 4e1bf1b6..b6f915a8 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -2557,7 +2557,7 @@ impl CodeGenerator for CompInfo {
             };
             // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does
             // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to
-            // non-zero padding bytes, especially when forwards/backwards compatability is
+            // non-zero padding bytes, especially when forwards/backwards compatibility is
             // involved.
             result.push(quote! {
                 impl #generics Default for #ty_for_impl {
diff --git a/bindgen/features.rs b/bindgen/features.rs
index fa3f20d7..6ac1d6a1 100644
--- a/bindgen/features.rs
+++ b/bindgen/features.rs
@@ -231,7 +231,6 @@ impl Default for RustFeatures {
 
 #[cfg(test)]
 mod test {
-    #![allow(unused_imports)]
     use super::*;
 
     #[test]
diff --git a/bindgen/ir/analysis/has_type_param_in_array.rs b/bindgen/ir/analysis/has_type_param_in_array.rs
index 088c08f5..6665547c 100644
--- a/bindgen/ir/analysis/has_type_param_in_array.rs
+++ b/bindgen/ir/analysis/has_type_param_in_array.rs
@@ -17,7 +17,7 @@ use crate::{HashMap, HashSet};
 /// * If T is a type alias, a templated alias or an indirection to another type,
 ///   it has type parameter in array if the type T refers to has.
 /// * If T is a compound type, it has array if any of base memter or field
-///   has type paramter in array.
+///   has type parameter in array.
 /// * If T is an instantiation of an abstract template definition, T has
 ///   type parameter in array if any of the template arguments or template definition
 ///   has.
diff --git a/bindgen/ir/analysis/mod.rs b/bindgen/ir/analysis/mod.rs
index 443384a4..8115944e 100644
--- a/bindgen/ir/analysis/mod.rs
+++ b/bindgen/ir/analysis/mod.rs
@@ -216,7 +216,7 @@ where
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{HashMap, HashSet};
+    use crate::HashSet;
 
     // Here we find the set of nodes that are reachable from any given
     // node. This is a lattice mapping nodes to subsets of all nodes. Our join
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index 26247cdc..c4465df9 100644
--- a/bindgen/ir/context.rs
+++ b/bindgen/ir/context.rs
@@ -30,6 +30,7 @@ use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeSet, HashMap as StdHashMap};
 use std::mem;
+use std::path::Path;
 
 /// An identifier for some kind of IR item.
 #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
@@ -376,6 +377,9 @@ pub(crate) struct BindgenContext {
     /// The translation unit for parsing.
     translation_unit: clang::TranslationUnit,
 
+    /// The translation unit for macro fallback parsing.
+    fallback_tu: Option<clang::FallbackTranslationUnit>,
+
     /// Target information that can be useful for some stuff.
     target_info: clang::TargetInfo,
 
@@ -584,6 +588,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
             collected_typerefs: false,
             in_codegen: false,
             translation_unit,
+            fallback_tu: None,
             target_info,
             options,
             generated_bindgen_complex: Cell::new(false),
@@ -2060,6 +2065,77 @@ If you encounter an error missing from this list, please file an issue or a PR!"
         &self.translation_unit
     }
 
+    /// Initialize fallback translation unit if it does not exist and
+    /// then return a mutable reference to the fallback translation unit.
+    pub(crate) fn try_ensure_fallback_translation_unit(
+        &mut self,
+    ) -> Option<&mut clang::FallbackTranslationUnit> {
+        if self.fallback_tu.is_none() {
+            let file = format!(
+                "{}/.macro_eval.c",
+                match self.options().clang_macro_fallback_build_dir {
+                    Some(ref path) => path.as_os_str().to_str()?,
+                    None => ".",
+                }
+            );
+
+            let index = clang::Index::new(false, false);
+
+            let mut c_args = Vec::new();
+            let mut pch_paths = Vec::new();
+            for input_header in self.options().input_headers.iter() {
+                let path = Path::new(input_header.as_ref());
+                let header_name = path
+                    .file_name()
+                    .and_then(|hn| hn.to_str())
+                    .map(|s| s.to_owned());
+                let header_path = path
+                    .parent()
+                    .and_then(|hp| hp.to_str())
+                    .map(|s| s.to_owned());
+
+                let (header, pch) = if let (Some(ref hp), Some(hn)) =
+                    (header_path, header_name)
+                {
+                    let header_path = if hp.is_empty() { "." } else { hp };
+                    let header = format!("{header_path}/{hn}");
+                    let pch_path = if let Some(ref path) =
+                        self.options().clang_macro_fallback_build_dir
+                    {
+                        path.as_os_str().to_str()?
+                    } else {
+                        header_path
+                    };
+                    (header, format!("{pch_path}/{hn}.pch"))
+                } else {
+                    return None;
+                };
+
+                let mut tu = clang::TranslationUnit::parse(
+                    &index,
+                    &header,
+                    &[
+                        "-x".to_owned().into_boxed_str(),
+                        "c-header".to_owned().into_boxed_str(),
+                    ],
+                    &[],
+                    clang_sys::CXTranslationUnit_ForSerialization,
+                )?;
+                tu.save(&pch).ok()?;
+
+                c_args.push("-include-pch".to_string().into_boxed_str());
+                c_args.push(pch.clone().into_boxed_str());
+                pch_paths.push(pch);
+            }
+
+            self.fallback_tu = Some(clang::FallbackTranslationUnit::new(
+                file, pch_paths, &c_args,
+            )?);
+        }
+
+        self.fallback_tu.as_mut()
+    }
+
     /// Have we parsed the macro named `macro_name` already?
     pub(crate) fn parsed_macro(&self, macro_name: &[u8]) -> bool {
         self.parsed_macros.contains_key(macro_name)
diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs
index a548ec88..a970cf15 100644
--- a/bindgen/ir/var.rs
+++ b/bindgen/ir/var.rs
@@ -389,9 +389,51 @@ impl ClangSubItemParser for Var {
     }
 }
 
+/// This function uses a [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] to parse each
+/// macro that cannot be parsed by the normal bindgen process for `#define`s.
+///
+/// To construct the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit], first precompiled
+/// headers are generated for all input headers. An empty temporary `.c` file is generated to pass
+/// to the translation unit. On the evaluation of each macro, a [`String`] is generated with the
+/// new contents of the empty file and passed in for reparsing. The precompiled headers and
+/// preservation of the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] across macro
+/// evaluations are both optimizations that have significantly improved the performance.
+fn parse_macro_clang_fallback(
+    ctx: &mut BindgenContext,
+    cursor: &clang::Cursor,
+) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
+    if !ctx.options().clang_macro_fallback {
+        return None;
+    }
+
+    let ftu = ctx.try_ensure_fallback_translation_unit()?;
+    let contents = format!("int main() {{ {}; }}", cursor.spelling(),);
+    ftu.reparse(&contents).ok()?;
+    // Children of root node of AST
+    let root_children = ftu.translation_unit().cursor().collect_children();
+    // Last child in root is function declaration
+    // Should be FunctionDecl
+    let main_func = root_children.last()?;
+    // Children should all be statements in function declaration
+    let all_stmts = main_func.collect_children();
+    // First child in all_stmts should be the statement containing the macro to evaluate
+    // Should be CompoundStmt
+    let macro_stmt = all_stmts.first()?;
+    // Children should all be expressions from the compound statement
+    let paren_exprs = macro_stmt.collect_children();
+    // First child in all_exprs is the expression utilizing the given macro to be evaluated
+    // Should  be ParenExpr
+    let paren = paren_exprs.first()?;
+
+    Some((
+        cursor.spelling().into_bytes(),
+        cexpr::expr::EvalResult::Int(Wrapping(paren.evaluate()?.as_int()?)),
+    ))
+}
+
 /// Try and parse a macro using all the macros parsed until now.
 fn parse_macro(
-    ctx: &BindgenContext,
+    ctx: &mut BindgenContext,
     cursor: &clang::Cursor,
 ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
     use cexpr::expr;
@@ -402,7 +444,7 @@ fn parse_macro(
 
     match parser.macro_definition(&cexpr_tokens) {
         Ok((_, (id, val))) => Some((id.into(), val)),
-        _ => None,
+        _ => parse_macro_clang_fallback(ctx, cursor),
     }
 }
 
diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs
index 3b3224ca..f374d207 100644
--- a/bindgen/options/mod.rs
+++ b/bindgen/options/mod.rs
@@ -21,9 +21,7 @@ use crate::HashMap;
 use crate::DEFAULT_ANON_FIELDS_PREFIX;
 
 use std::env;
-#[cfg(feature = "experimental")]
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
 use as_args::AsArgs;
@@ -1983,7 +1981,7 @@ options! {
         },
         as_args: "--wrap-unsafe-ops",
     },
-    /// Patterns for functions whose ABI should be overriden.
+    /// Patterns for functions whose ABI should be overridden.
     abi_overrides: HashMap<Abi, RegexSet> {
         methods: {
             regex_option! {
@@ -2107,5 +2105,38 @@ options! {
             }
         },
         as_args: "--emit-diagnostics",
+    },
+    /// Whether to use Clang evaluation on temporary files as a fallback for macros that fail to
+    /// parse.
+    clang_macro_fallback: bool {
+        methods: {
+            /// Use Clang as a fallback for macros that fail to parse using `CExpr`.
+            ///
+            /// This uses a workaround to evaluate each macro in a temporary file. Because this
+            /// results in slower compilation, this option is opt-in.
+            pub fn clang_macro_fallback(mut self) -> Self {
+                self.options.clang_macro_fallback = true;
+                self
+            }
+        },
+        as_args: "--clang-macro-fallback",
+    }
+    /// Path to use for temporary files created by clang macro fallback code like precompiled
+    /// headers.
+    clang_macro_fallback_build_dir: Option<PathBuf> {
+        methods: {
+            /// Set a path to a directory to which `.c` and `.h.pch` files should be written for the
+            /// purpose of using clang to evaluate macros that can't be easily parsed.
+            ///
+            /// The default location for `.h.pch` files is the directory that the corresponding
+            /// `.h` file is located in. The default for the temporary `.c` file used for clang
+            /// parsing is the current working directory. Both of these defaults are overridden
+            /// by this option.
+            pub fn clang_macro_fallback_build_dir<P: AsRef<Path>>(mut self, path: P) -> Self {
+                self.options.clang_macro_fallback_build_dir = Some(path.as_ref().to_owned());
+                self
+            }
+        },
+        as_args: "--clang-macro-fallback-build-dir",
     }
 }
diff --git a/book/src/cpp.md b/book/src/cpp.md
index 9b451b9d..db368f67 100644
--- a/book/src/cpp.md
+++ b/book/src/cpp.md
@@ -154,6 +154,6 @@ instance.assume_init_mut().method();
 ```
 
 You can easily verify this fact if you provide a implementation for `MyClass`
-and `method` that prints the the `this` pointer address. However, you can
+and `method` that prints the `this` pointer address. However, you can
 ignore this fact if you know that the original C++ code does not rely on the
 instance address in its internal logic.
diff --git a/book/src/non-system-libraries.md b/book/src/non-system-libraries.md
index d5d288d1..b080db80 100644
--- a/book/src/non-system-libraries.md
+++ b/book/src/non-system-libraries.md
@@ -17,8 +17,6 @@ Given that the library has not been compiled yet, we need to modify the
 library:
 
 ```rust,ignore
-extern crate bindgen;
-
 use std::env;
 use std::path::PathBuf;
 
diff --git a/book/src/using-unions.md b/book/src/using-unions.md
index 9e8e9b99..5ae764a3 100644
--- a/book/src/using-unions.md
+++ b/book/src/using-unions.md
@@ -66,11 +66,11 @@ When using the `union` builtin type, there are two choices for initialization:
 mod bindings_builtin_union;
 
 fn union_builtin() {
-    // Initalize the union to zero
+    // Initialize the union to zero
     let x = bindings_builtin_union::greek_t::default();
 
     // If `--with-derive-default` option is not used, the following may be used
-    //   to initalize the union to zero:
+    //   to initialize the union to zero:
     let x = unsafe { std::mem::zeroed::<bindings_builtin_union::greek_t>() };
 
     // Or, it is possible to initialize exactly one variant of the enum:


Test patch:
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_attributes.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_attributes.rs
index 7682884b..a1fb1b0c 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_attributes.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_attributes.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: unsafe extern "C" fn(
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_required.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_required.rs
index 6fd97e4a..5c929ffc 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_required.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_required.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: unsafe extern "C" fn(
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_simple.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_simple.rs
index cdacf3ab..9a4cfaf5 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_simple.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_simple.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_template.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_template.rs
index 65c36e48..65f079be 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_template.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_template.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_allowlist.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_allowlist.rs
index 06fffc3d..e65176b8 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_allowlist.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_allowlist.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_blocklist.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_blocklist.rs
index 9273583a..49081598 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_blocklist.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_blocklist.rs
@@ -37,7 +37,6 @@ impl X {
         __bindgen_tmp.assume_init()
     }
 }
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_class.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_class.rs
index dd0544b0..694d7e4a 100644
--- a/bindgen-tests/tests/expectations/tests/dynamic_loading_with_class.rs
+++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_with_class.rs
@@ -37,7 +37,6 @@ impl A {
         __bindgen_tmp.assume_init()
     }
 }
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/expectations/tests/enum-doc-bitfield.rs b/bindgen-tests/tests/expectations/tests/enum-doc-bitfield.rs
index e6e9ffaa..ba73a8ea 100644
--- a/bindgen-tests/tests/expectations/tests/enum-doc-bitfield.rs
+++ b/bindgen-tests/tests/expectations/tests/enum-doc-bitfield.rs
@@ -4,11 +4,11 @@ impl B {
     pub const VAR_A: B = B(0);
 }
 impl B {
-    /// Document field with preceeding star
+    /// Document field with preceding star
     pub const VAR_B: B = B(1);
 }
 impl B {
-    /// Document field with preceeding exclamation
+    /// Document field with preceding exclamation
     pub const VAR_C: B = B(2);
 }
 impl B {
@@ -20,7 +20,7 @@ impl B {
     pub const VAR_E: B = B(4);
 }
 impl B {
-    /** Document field with preceeding star, with a loong long multiline
+    /** Document field with preceding star, with a loong long multiline
  comment.
 
  Very interesting documentation, definitely.*/
diff --git a/bindgen-tests/tests/expectations/tests/enum-doc-mod.rs b/bindgen-tests/tests/expectations/tests/enum-doc-mod.rs
index c54410e2..2b18b35d 100644
--- a/bindgen-tests/tests/expectations/tests/enum-doc-mod.rs
+++ b/bindgen-tests/tests/expectations/tests/enum-doc-mod.rs
@@ -4,15 +4,15 @@ pub mod B {
     pub type Type = ::std::os::raw::c_uint;
     /// Document field with three slashes
     pub const VAR_A: Type = 0;
-    /// Document field with preceeding star
+    /// Document field with preceding star
     pub const VAR_B: Type = 1;
-    /// Document field with preceeding exclamation
+    /// Document field with preceding exclamation
     pub const VAR_C: Type = 2;
     ///< Document field with following star
     pub const VAR_D: Type = 3;
     ///< Document field with following exclamation
     pub const VAR_E: Type = 4;
-    /** Document field with preceeding star, with a loong long multiline
+    /** Document field with preceding star, with a loong long multiline
  comment.
 
  Very interesting documentation, definitely.*/
diff --git a/bindgen-tests/tests/expectations/tests/enum-doc-rusty.rs b/bindgen-tests/tests/expectations/tests/enum-doc-rusty.rs
index a83d2dc4..3eec0759 100644
--- a/bindgen-tests/tests/expectations/tests/enum-doc-rusty.rs
+++ b/bindgen-tests/tests/expectations/tests/enum-doc-rusty.rs
@@ -5,15 +5,15 @@
 pub enum B {
     /// Document field with three slashes
     VAR_A = 0,
-    /// Document field with preceeding star
+    /// Document field with preceding star
     VAR_B = 1,
-    /// Document field with preceeding exclamation
+    /// Document field with preceding exclamation
     VAR_C = 2,
     ///< Document field with following star
     VAR_D = 3,
     ///< Document field with following exclamation
     VAR_E = 4,
-    /** Document field with preceeding star, with a loong long multiline
+    /** Document field with preceding star, with a loong long multiline
  comment.
 
  Very interesting documentation, definitely.*/
diff --git a/bindgen-tests/tests/expectations/tests/enum-doc.rs b/bindgen-tests/tests/expectations/tests/enum-doc.rs
index ee0ca23b..98a7eed8 100644
--- a/bindgen-tests/tests/expectations/tests/enum-doc.rs
+++ b/bindgen-tests/tests/expectations/tests/enum-doc.rs
@@ -1,15 +1,15 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
 /// Document field with three slashes
 pub const B_VAR_A: B = 0;
-/// Document field with preceeding star
+/// Document field with preceding star
 pub const B_VAR_B: B = 1;
-/// Document field with preceeding exclamation
+/// Document field with preceding exclamation
 pub const B_VAR_C: B = 2;
 ///< Document field with following star
 pub const B_VAR_D: B = 3;
 ///< Document field with following exclamation
 pub const B_VAR_E: B = 4;
-/** Document field with preceeding star, with a loong long multiline
+/** Document field with preceding star, with a loong long multiline
  comment.
 
  Very interesting documentation, definitely.*/
diff --git a/bindgen-tests/tests/expectations/tests/issue-537-repr-packed-n.rs b/bindgen-tests/tests/expectations/tests/issue-537-repr-packed-n.rs
index 30425515..0142673f 100644
--- a/bindgen-tests/tests/expectations/tests/issue-537-repr-packed-n.rs
+++ b/bindgen-tests/tests/expectations/tests/issue-537-repr-packed-n.rs
@@ -23,7 +23,7 @@ fn bindgen_test_layout_AlignedToOne() {
         "Offset of field: AlignedToOne::i",
     );
 }
-/// This should be be packed because Rust 1.33 has `#[repr(packed(N))]`.
+/// This should be packed because Rust 1.33 has `#[repr(packed(N))]`.
 #[repr(C, packed(2))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct AlignedToTwo {
@@ -75,7 +75,7 @@ fn bindgen_test_layout_PackedToOne() {
         "Offset of field: PackedToOne::y",
     );
 }
-/// This should be be packed because Rust 1.33 has `#[repr(packed(N))]`.
+/// This should be packed because Rust 1.33 has `#[repr(packed(N))]`.
 #[repr(C, packed(2))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct PackedToTwo {
diff --git a/bindgen-tests/tests/expectations/tests/issue-753.rs b/bindgen-tests/tests/expectations/tests/issue-753.rs
new file mode 100644
index 00000000..3119ec56
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/issue-753.rs
@@ -0,0 +1,4 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+pub const CONST: u32 = 5;
+pub const OTHER_CONST: u32 = 6;
+pub const LARGE_CONST: u32 = 1536;
diff --git a/bindgen-tests/tests/expectations/tests/libclang-9/issue-753.rs b/bindgen-tests/tests/expectations/tests/libclang-9/issue-753.rs
new file mode 100644
index 00000000..fe64295a
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/libclang-9/issue-753.rs
@@ -0,0 +1,1 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
\ No newline at end of file
diff --git a/bindgen-tests/tests/expectations/tests/wrap_unsafe_ops_dynamic_loading_simple.rs b/bindgen-tests/tests/expectations/tests/wrap_unsafe_ops_dynamic_loading_simple.rs
index 968f10f6..2f5b4cc5 100644
--- a/bindgen-tests/tests/expectations/tests/wrap_unsafe_ops_dynamic_loading_simple.rs
+++ b/bindgen-tests/tests/expectations/tests/wrap_unsafe_ops_dynamic_loading_simple.rs
@@ -1,5 +1,4 @@
 #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
-extern crate libloading;
 pub struct TestLib {
     __library: ::libloading::Library,
     pub foo: Result<
diff --git a/bindgen-tests/tests/headers/enum-doc.h b/bindgen-tests/tests/headers/enum-doc.h
index 58e2c69e..7a2f425c 100644
--- a/bindgen-tests/tests/headers/enum-doc.h
+++ b/bindgen-tests/tests/headers/enum-doc.h
@@ -2,14 +2,14 @@
 enum B {
     /// Document field with three slashes
     VAR_A = 0,
-    /** Document field with preceeding star */
+    /** Document field with preceding star */
     VAR_B = 1,
-    /*! Document field with preceeding exclamation */
+    /*! Document field with preceding exclamation */
     VAR_C = 2,
     VAR_D = 3, /**< Document field with following star */
     VAR_E = 4, /*!< Document field with following exclamation */
     /**
-     * Document field with preceeding star, with a loong long multiline
+     * Document field with preceding star, with a loong long multiline
      * comment.
      *
      * Very interesting documentation, definitely.
diff --git a/bindgen-tests/tests/headers/issue-537-repr-packed-n.h b/bindgen-tests/tests/headers/issue-537-repr-packed-n.h
index f4c0070a..7beaf883 100644
--- a/bindgen-tests/tests/headers/issue-537-repr-packed-n.h
+++ b/bindgen-tests/tests/headers/issue-537-repr-packed-n.h
@@ -6,7 +6,7 @@ struct AlignedToOne {
     int i;
 } __attribute__ ((packed,aligned(1)));
 
-/// This should be be packed because Rust 1.33 has `#[repr(packed(N))]`.
+/// This should be packed because Rust 1.33 has `#[repr(packed(N))]`.
 struct AlignedToTwo {
     int i;
 } __attribute__ ((packed,aligned(2)));
@@ -25,7 +25,7 @@ struct PackedToOne {
 
 #pragma pack(2)
 
-/// This should be be packed because Rust 1.33 has `#[repr(packed(N))]`.
+/// This should be packed because Rust 1.33 has `#[repr(packed(N))]`.
 struct PackedToTwo {
     int x;
     int y;
diff --git a/bindgen-tests/tests/headers/issue-753.h b/bindgen-tests/tests/headers/issue-753.h
new file mode 100644
index 00000000..94bb8e1c
--- /dev/null
+++ b/bindgen-tests/tests/headers/issue-753.h
@@ -0,0 +1,7 @@
+// bindgen-flags: --clang-macro-fallback
+
+#define UINT32_C(c) c ## U
+
+#define CONST UINT32_C(5)
+#define OTHER_CONST UINT32_C(6)
+#define LARGE_CONST UINT32_C(6 << 8)
diff --git a/bindgen-tests/tests/headers/template-param-usage-7.hpp b/bindgen-tests/tests/headers/template-param-usage-7.hpp
index 99d4cc71..3d70cee1 100644
--- a/bindgen-tests/tests/headers/template-param-usage-7.hpp
+++ b/bindgen-tests/tests/headers/template-param-usage-7.hpp
@@ -6,5 +6,5 @@ class DoesNotUseU {
     V v;
 };
 
-// The bool should go away becuase U is not used.
+// The bool should go away because U is not used.
 using Alias = DoesNotUseU<int, bool, char>;
diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h
index 131b7ab1..2be7bd93 100644
--- a/bindgen-tests/tests/headers/wrap-static-fns.h
+++ b/bindgen-tests/tests/headers/wrap-static-fns.h
@@ -1,7 +1,7 @@
 // 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
+// to avoid polluting the expectation tests we put the stdarg.h behind a conditional
 // variable only used in bindgen-integration
 #ifdef USE_VA_HEADER
 #include <stdarg.h>
diff --git a/bindgen-tests/tests/quickchecking/src/bin.rs b/bindgen-tests/tests/quickchecking/src/bin.rs
index 7f1307e1..fcd56652 100644
--- a/bindgen-tests/tests/quickchecking/src/bin.rs
+++ b/bindgen-tests/tests/quickchecking/src/bin.rs
@@ -14,8 +14,6 @@
 //! ```
 //!
 #![deny(missing_docs)]
-extern crate clap;
-extern crate quickchecking;
 
 use clap::{Arg, ArgAction, Command};
 use std::path::PathBuf;
diff --git a/bindgen-tests/tests/quickchecking/src/lib.rs b/bindgen-tests/tests/quickchecking/src/lib.rs
index 631c1c67..38da62f6 100644
--- a/bindgen-tests/tests/quickchecking/src/lib.rs
+++ b/bindgen-tests/tests/quickchecking/src/lib.rs
@@ -3,8 +3,6 @@
 //! ## Example
 //!
 //! ```rust
-//! extern crate quickcheck;
-//! extern crate quickchecking;
 //! use quickcheck::{Arbitrary, Gen};
 //! use quickchecking::fuzzers;
 //!
@@ -20,8 +18,6 @@
 #![deny(missing_docs)]
 #[macro_use]
 extern crate lazy_static;
-extern crate quickcheck;
-extern crate tempfile;
 
 use quickcheck::{Gen, QuickCheck, TestResult};
 use std::error::Error;
diff --git a/bindgen-tests/tests/quickchecking/tests/fuzzed-c-headers.rs b/bindgen-tests/tests/quickchecking/tests/fuzzed-c-headers.rs
index e394efe3..0735a70c 100644
--- a/bindgen-tests/tests/quickchecking/tests/fuzzed-c-headers.rs
+++ b/bindgen-tests/tests/quickchecking/tests/fuzzed-c-headers.rs
@@ -1,6 +1,3 @@
-extern crate quickcheck;
-extern crate quickchecking;
-
 use quickcheck::{Arbitrary, Gen};
 use quickchecking::fuzzers::{
     ArrayDimensionC, BaseTypeC, BasicTypeDeclarationC, DeclarationC,
diff --git a/bindgen-tests/tests/stylo_sanity.rs b/bindgen-tests/tests/stylo_sanity.rs
index e9ec69bc..7b94e298 100755
--- a/bindgen-tests/tests/stylo_sanity.rs
+++ b/bindgen-tests/tests/stylo_sanity.rs
@@ -1,7 +1,3 @@
-// Don't want to copy that nasty `cfg` below...
-#[allow(unused_extern_crates)]
-extern crate bindgen;
-
 /// A sanity test that we can generate bindings for Stylo.
 ///
 /// We don't assert on expected output because its just too big. The output will
diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs
index c096b2e8..e6c038a0 100644
--- a/bindgen-tests/tests/tests.rs
+++ b/bindgen-tests/tests/tests.rs
@@ -1,9 +1,3 @@
-extern crate bindgen;
-extern crate clap;
-#[cfg(feature = "logging")]
-extern crate env_logger;
-extern crate shlex;
-
 use bindgen::{clang_version, Builder};
 use owo_colors::{OwoColorize, Style};
 use similar::{ChangeTag, TextDiff};