diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 203da256..de46bb22 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -3048,6 +3048,50 @@ impl CodeGenerator for Enum { } } +/// Enum for the default type of macro constants. +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum MacroTypeVariation { + /// Use i32 or i64 + Signed, + /// Use u32 or u64 + Unsigned, +} + +impl MacroTypeVariation { + /// Convert a `MacroTypeVariation` to its str representation. + pub fn as_str(&self) -> &str { + match self { + MacroTypeVariation::Signed => "signed", + MacroTypeVariation::Unsigned => "unsigned", + } + } +} + +impl Default for MacroTypeVariation { + fn default() -> MacroTypeVariation { + MacroTypeVariation::Unsigned + } +} + +impl std::str::FromStr for MacroTypeVariation { + type Err = std::io::Error; + + /// Create a `MacroTypeVariation` from a string. + fn from_str(s: &str) -> Result { + match s { + "signed" => Ok(MacroTypeVariation::Signed), + "unsigned" => Ok(MacroTypeVariation::Unsigned), + _ => Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + concat!( + "Got an invalid MacroTypeVariation. Accepted values ", + "are 'signed' and 'unsigned'" + ), + )), + } + } +} + /// Enum for how aliases should be translated. #[derive(Copy, Clone, PartialEq, Debug)] pub enum AliasVariation { diff --git a/src/ir/var.rs b/src/ir/var.rs index ef963503..c6f121d7 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -1,5 +1,6 @@ //! Intermediate representation of variables. +use super::super::codegen::MacroTypeVariation; use super::context::{BindgenContext, TypeId}; use super::dot::DotAttributes; use super::function::cursor_mangling; @@ -117,9 +118,12 @@ impl DotAttributes for Var { } // TODO(emilio): we could make this more (or less) granular, I guess. -fn default_macro_constant_type(value: i64) -> IntKind { - if value < 0 { - if value < i32::min_value() as i64 { +fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind { + if value < 0 || + ctx.options().default_macro_constant_type == + MacroTypeVariation::Signed + { + if value < i32::min_value() as i64 || value > i32::max_value() as i64 { IntKind::I64 } else { IntKind::I32 @@ -264,7 +268,7 @@ impl ClangSubItemParser for Var { .parse_callbacks() .and_then(|c| c.int_macro(&name, value)) .unwrap_or_else(|| { - default_macro_constant_type(value) + default_macro_constant_type(&ctx, value) }); (TypeKind::Int(kind), VarType::Int(value)) diff --git a/src/lib.rs b/src/lib.rs index 9bbefaad..0bcdf789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ doc_mod!(ir, ir_docs); doc_mod!(parse, parse_docs); doc_mod!(regex_set, regex_set_docs); -pub use crate::codegen::{AliasVariation, EnumVariation}; +pub use crate::codegen::{AliasVariation, EnumVariation, MacroTypeVariation}; use crate::features::RustFeatures; pub use crate::features::{ RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, @@ -267,6 +267,12 @@ impl Builder { ) } + if self.options.default_macro_constant_type != Default::default() { + output_vector.push("--default-macro-constant-type".into()); + output_vector + .push(self.options.default_macro_constant_type.as_str().into()); + } + if self.options.default_alias_style != Default::default() { output_vector.push("--default-alias-style".into()); output_vector @@ -872,6 +878,15 @@ impl Builder { self } + /// Set the default type for macro constants + pub fn default_macro_constant_type( + mut self, + arg: codegen::MacroTypeVariation, + ) -> Builder { + self.options.default_macro_constant_type = arg; + self + } + /// Set the default style of code to generate for typedefs pub fn default_alias_style( mut self, @@ -1513,6 +1528,9 @@ struct BindgenOptions { /// The enum patterns to mark an enum as a set of constants. constified_enums: RegexSet, + /// The default type for C macro constants. + default_macro_constant_type: codegen::MacroTypeVariation, + /// The default style of code to generate for typedefs. default_alias_style: codegen::AliasVariation, @@ -1800,6 +1818,7 @@ impl Default for BindgenOptions { rustified_non_exhaustive_enums: Default::default(), constified_enums: Default::default(), constified_enum_modules: Default::default(), + default_macro_constant_type: Default::default(), default_alias_style: Default::default(), type_alias: Default::default(), new_type_alias: Default::default(), diff --git a/src/options.rs b/src/options.rs index 1ba349a9..a850dbbb 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,6 +1,7 @@ use bindgen::{ - builder, AliasVariation, Builder, CodegenConfig, EnumVariation, RustTarget, - DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS, + builder, AliasVariation, Builder, CodegenConfig, EnumVariation, + MacroTypeVariation, RustTarget, DEFAULT_ANON_FIELDS_PREFIX, + RUST_TARGET_STRINGS, }; use clap::{App, Arg}; use std::fs::File; @@ -87,6 +88,13 @@ where .takes_value(true) .multiple(true) .number_of_values(1), + Arg::with_name("default-macro-constant-type") + .long("default-macro-constant-type") + .help("The default signed/unsigned type for C macro constants.") + .value_name("variant") + .default_value("unsigned") + .possible_values(&["signed", "unsigned"]) + .multiple(false), Arg::with_name("default-alias-style") .long("default-alias-style") .help("The default style of code used to generate typedefs.") @@ -522,6 +530,11 @@ where } } + if let Some(variant) = matches.value_of("default-macro-constant-type") { + builder = builder + .default_macro_constant_type(MacroTypeVariation::from_str(variant)?) + } + if let Some(variant) = matches.value_of("default-alias-style") { builder = builder.default_alias_style(AliasVariation::from_str(variant)?); diff --git a/tests/expectations/tests/default-macro-constant-type-signed.rs b/tests/expectations/tests/default-macro-constant-type-signed.rs new file mode 100644 index 00000000..eda3117d --- /dev/null +++ b/tests/expectations/tests/default-macro-constant-type-signed.rs @@ -0,0 +1,42 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +pub const N0: i32 = 0; +pub const N1: i32 = 1; +pub const N2: i32 = 2; +pub const N_1: i32 = -1; +pub const N_2: i32 = -2; +pub const MAX_U32: i64 = 4294967295; +pub const MAX_I32: i32 = 2147483647; +pub const MAX_I32_Plus1: i64 = 2147483648; +pub const MAX_U32_Plus1: i64 = 4294967296; +pub const MAX_I32_Minus1: i32 = 2147483646; +pub const MAX_U32_Minus1: i64 = 4294967294; +pub const MIN_U32: i32 = 0; +pub const MIN_I32: i32 = -2147483648; +pub const MIN_U32_Plus1: i32 = 1; +pub const MIN_I32_Plus1: i32 = -2147483647; +pub const MIN_U32_Minus1: i32 = -1; +pub const MIN_I32_Minus1: i64 = -2147483649; +pub const LONG12: i64 = 123456789012; +pub const LONG_12: i64 = -123456789012; +extern "C" { + pub fn foo( + arg1: ::std::os::raw::c_int, + arg2: ::std::os::raw::c_int, + arg3: ::std::os::raw::c_uint, + arg4: ::std::os::raw::c_char, + arg5: ::std::os::raw::c_uchar, + arg6: ::std::os::raw::c_schar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn bar( + arg1: ::std::os::raw::c_long, + arg2: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_long; +} diff --git a/tests/expectations/tests/default-macro-constant-type-unsigned.rs b/tests/expectations/tests/default-macro-constant-type-unsigned.rs new file mode 100644 index 00000000..241443aa --- /dev/null +++ b/tests/expectations/tests/default-macro-constant-type-unsigned.rs @@ -0,0 +1,42 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +pub const N0: u32 = 0; +pub const N1: u32 = 1; +pub const N2: u32 = 2; +pub const N_1: i32 = -1; +pub const N_2: i32 = -2; +pub const MAX_U32: u32 = 4294967295; +pub const MAX_I32: u32 = 2147483647; +pub const MAX_I32_Plus1: u32 = 2147483648; +pub const MAX_U32_Plus1: u64 = 4294967296; +pub const MAX_I32_Minus1: u32 = 2147483646; +pub const MAX_U32_Minus1: u32 = 4294967294; +pub const MIN_U32: u32 = 0; +pub const MIN_I32: i32 = -2147483648; +pub const MIN_U32_Plus1: u32 = 1; +pub const MIN_I32_Plus1: i32 = -2147483647; +pub const MIN_U32_Minus1: i32 = -1; +pub const MIN_I32_Minus1: i64 = -2147483649; +pub const LONG12: u64 = 123456789012; +pub const LONG_12: i64 = -123456789012; +extern "C" { + pub fn foo( + arg1: ::std::os::raw::c_int, + arg2: ::std::os::raw::c_int, + arg3: ::std::os::raw::c_uint, + arg4: ::std::os::raw::c_char, + arg5: ::std::os::raw::c_uchar, + arg6: ::std::os::raw::c_schar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn bar( + arg1: ::std::os::raw::c_long, + arg2: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_long; +} diff --git a/tests/expectations/tests/default-macro-constant-type.rs b/tests/expectations/tests/default-macro-constant-type.rs new file mode 100644 index 00000000..241443aa --- /dev/null +++ b/tests/expectations/tests/default-macro-constant-type.rs @@ -0,0 +1,42 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +pub const N0: u32 = 0; +pub const N1: u32 = 1; +pub const N2: u32 = 2; +pub const N_1: i32 = -1; +pub const N_2: i32 = -2; +pub const MAX_U32: u32 = 4294967295; +pub const MAX_I32: u32 = 2147483647; +pub const MAX_I32_Plus1: u32 = 2147483648; +pub const MAX_U32_Plus1: u64 = 4294967296; +pub const MAX_I32_Minus1: u32 = 2147483646; +pub const MAX_U32_Minus1: u32 = 4294967294; +pub const MIN_U32: u32 = 0; +pub const MIN_I32: i32 = -2147483648; +pub const MIN_U32_Plus1: u32 = 1; +pub const MIN_I32_Plus1: i32 = -2147483647; +pub const MIN_U32_Minus1: i32 = -1; +pub const MIN_I32_Minus1: i64 = -2147483649; +pub const LONG12: u64 = 123456789012; +pub const LONG_12: i64 = -123456789012; +extern "C" { + pub fn foo( + arg1: ::std::os::raw::c_int, + arg2: ::std::os::raw::c_int, + arg3: ::std::os::raw::c_uint, + arg4: ::std::os::raw::c_char, + arg5: ::std::os::raw::c_uchar, + arg6: ::std::os::raw::c_schar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn bar( + arg1: ::std::os::raw::c_long, + arg2: ::std::os::raw::c_longlong, + ) -> ::std::os::raw::c_long; +} diff --git a/tests/headers/default-macro-constant-type-signed.h b/tests/headers/default-macro-constant-type-signed.h new file mode 100644 index 00000000..da3f1344 --- /dev/null +++ b/tests/headers/default-macro-constant-type-signed.h @@ -0,0 +1,3 @@ +// bindgen-flags: --default-macro-constant-type signed +// All values are i32 if they fit; otherwise i64. +#include "default-macro-constant-type.h" diff --git a/tests/headers/default-macro-constant-type-unsigned.h b/tests/headers/default-macro-constant-type-unsigned.h new file mode 100644 index 00000000..1078e852 --- /dev/null +++ b/tests/headers/default-macro-constant-type-unsigned.h @@ -0,0 +1,3 @@ +// bindgen-flags: --default-macro-constant-type unsigned +// Negative values are i32 or i64; others are u32 or u64. +#include "default-macro-constant-type.h" diff --git a/tests/headers/default-macro-constant-type.h b/tests/headers/default-macro-constant-type.h new file mode 100644 index 00000000..d11941b4 --- /dev/null +++ b/tests/headers/default-macro-constant-type.h @@ -0,0 +1,34 @@ +// Test default of --default-macro-constant-type +// Negative values are i32 or i64; others are u32 or u64. + +#define N0 0 +#define N1 1ULL +#define N2 2ULL + +#define N_1 (-1LL) +#define N_2 (-2LL) + +#define MAX_U32 0xFFFFFFFFULL +#define MAX_I32 (0x80000000ULL - 1) + +#define MAX_I32_Plus1 (MAX_I32 + 1) +#define MAX_U32_Plus1 (MAX_U32 + 1) + +#define MAX_I32_Minus1 (MAX_I32 - 1) +#define MAX_U32_Minus1 (MAX_U32 - 1) + +#define MIN_U32 0 +#define MIN_I32 (- (1ULL<<31)) + +#define MIN_U32_Plus1 (MIN_U32 + 1) +#define MIN_I32_Plus1 (MIN_I32 + 1) + +#define MIN_U32_Minus1 (MIN_U32 - 1) +#define MIN_I32_Minus1 (MIN_I32 - 1) + +#define LONG12 123456789012ULL +#define LONG_12 (- 123456789012ULL) + +// Function parameter and return types are not affected. +int foo(int, signed, unsigned, char, unsigned char, signed char); +long bar(long, long long);