Add BindgenError
diff --git a/src/lib.rs b/src/lib.rs
index f3912e8..4ff72cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1444,6 +1444,7 @@
     }
 
     /// Generate the Rust bindings using the options built up thus far.
+    #[deprecated(since = "0.59.3", note = "please use `gen` instead")]
     pub fn generate(mut self) -> Result<Bindings, ()> {
         // Add any extra arguments from the environment to the clang command line.
         if let Some(extra_clang_args) =
@@ -1475,6 +1476,41 @@
                 }),
         );
 
+        Bindings::generate(self.options).map_err(|_| ())
+    }
+
+    /// Generate the Rust bindings using the options built up thus far, or `Err` on failure.
+    pub fn gen(mut self) -> Result<Bindings, BindgenError> {
+        // Add any extra arguments from the environment to the clang command line.
+        if let Some(extra_clang_args) =
+            get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS")
+        {
+            // Try to parse it with shell quoting. If we fail, make it one single big argument.
+            if let Some(strings) = shlex::split(&extra_clang_args) {
+                self.options.clang_args.extend(strings);
+            } else {
+                self.options.clang_args.push(extra_clang_args);
+            };
+        }
+
+        // Transform input headers to arguments on the clang command line.
+        self.options.input_header = self.input_headers.pop();
+        self.options.extra_input_headers = self.input_headers;
+        self.options.clang_args.extend(
+            self.options.extra_input_headers.iter().flat_map(|header| {
+                iter::once("-include".into())
+                    .chain(iter::once(header.to_string()))
+            }),
+        );
+
+        self.options.input_unsaved_files.extend(
+            self.input_header_contents
+                .drain(..)
+                .map(|(name, contents)| {
+                    clang::UnsavedFile::new(&name, &contents)
+                }),
+        );
+
         Bindings::generate(self.options)
     }
 
@@ -2146,6 +2182,28 @@
 #[cfg(not(feature = "runtime"))]
 fn ensure_libclang_is_loaded() {}
 
+/// Error type for rust-bindgen.
+#[derive(Debug)]
+pub enum BindgenError {
+    /// Any provided header was invalid.
+    InvalidHeader(String),
+    /// Clang diagnosed an error.
+    ClangDiagnostic(String),
+}
+
+impl std::fmt::Display for BindgenError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            BindgenError::InvalidHeader(message) => {
+                write!(f, "invalid header: {}", message)
+            }
+            BindgenError::ClangDiagnostic(message) => {
+                write!(f, "clang diagnosed error: {}", message)
+            }
+        }
+    }
+}
+
 /// Generated Rust bindings.
 #[derive(Debug)]
 pub struct Bindings {
@@ -2202,7 +2260,7 @@
     /// Generate bindings for the given options.
     pub(crate) fn generate(
         mut options: BindgenOptions,
-    ) -> Result<Bindings, ()> {
+    ) -> Result<Bindings, BindgenError> {
         ensure_libclang_is_loaded();
 
         #[cfg(feature = "runtime")]
@@ -2322,20 +2380,23 @@
         if let Some(h) = options.input_header.as_ref() {
             if let Ok(md) = std::fs::metadata(h) {
                 if md.is_dir() {
-                    eprintln!("error: '{}' is a folder", h);
-                    return Err(());
+                    return Err(BindgenError::InvalidHeader(format!(
+                        "error: '{}' is a folder",
+                        h
+                    )));
                 }
                 if !can_read(&md.permissions()) {
-                    eprintln!(
+                    return Err(BindgenError::InvalidHeader(format!(
                         "error: insufficient permissions to read '{}'",
                         h
-                    );
-                    return Err(());
+                    )));
                 }
                 options.clang_args.push(h.clone())
             } else {
-                eprintln!("error: header '{}' does not exist.", h);
-                return Err(());
+                return Err(BindgenError::InvalidHeader(format!(
+                    "error: header '{}' does not exist.",
+                    h
+                )));
             }
         }
 
@@ -2556,19 +2617,24 @@
 }
 
 /// Parse the Clang AST into our `Item` internal representation.
-fn parse(context: &mut BindgenContext) -> Result<(), ()> {
+fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> {
     use clang_sys::*;
 
-    let mut any_error = false;
+    let mut error = None;
     for d in context.translation_unit().diags().iter() {
         let msg = d.format();
         let is_err = d.severity() >= CXDiagnostic_Error;
-        eprintln!("{}, err: {}", msg, is_err);
-        any_error |= is_err;
+        if is_err {
+            let error = error.get_or_insert_with(String::new);
+            error.push_str(&msg);
+            error.push('\n');
+        } else {
+            eprintln!("clang diag: {}", msg);
+        }
     }
 
-    if any_error {
-        return Err(());
+    if let Some(message) = error {
+        return Err(BindgenError::ClangDiagnostic(message));
     }
 
     let cursor = context.translation_unit().cursor();