From ea4164c85c6a305379e4cc70465aae15afedf3d7 Mon Sep 17 00:00:00 2001 From: Antoni Simka Date: Tue, 15 Dec 2020 17:18:16 +0100 Subject: [PATCH] Add option to fit macro consts into smaller types Add a `--fit-macro-constant-types` option to make bindgen try to fit macro integer constants into types smaller than u32/i32. Useful especially when dealing with 8/16-bit architectures. Closes #1945 --- src/ir/var.rs | 54 +++++++++++++++---- src/lib.rs | 14 +++++ src/options.rs | 7 +++ .../default-macro-constant-type-signed.rs | 12 +++++ .../default-macro-constant-type-unsigned.rs | 12 +++++ .../tests/default-macro-constant-type.rs | 12 +++++ .../tests/fit-macro-constant-types.rs | 54 +++++++++++++++++++ tests/headers/default-macro-constant-type.h | 18 +++++++ tests/headers/fit-macro-constant-types.h | 4 ++ 9 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 tests/expectations/tests/fit-macro-constant-types.rs create mode 100644 tests/headers/fit-macro-constant-types.h diff --git a/src/ir/var.rs b/src/ir/var.rs index c6f121d74e..64f15703c1 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -117,21 +117,53 @@ impl DotAttributes for Var { } } -// TODO(emilio): we could make this more (or less) granular, I guess. 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 + if ctx.options().fit_macro_constants { + 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 if value < i16::min_value() as i64 || + value > i16::max_value() as i64 + { + IntKind::I32 + } else if value < i8::min_value() as i64 || + value > i8::max_value() as i64 + { + IntKind::I16 + } else { + IntKind::I8 + } + } else if value > u32::max_value() as i64 { + IntKind::U64 + } else if value > u16::max_value() as i64 { + IntKind::U32 + } else if value > u8::max_value() as i64 { + IntKind::U16 } else { - IntKind::I32 + IntKind::U8 } - } else if value > u32::max_value() as i64 { - IntKind::U64 } else { - IntKind::U32 + 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 + } + } else if value > u32::max_value() as i64 { + IntKind::U64 + } else { + IntKind::U32 + } } } diff --git a/src/lib.rs b/src/lib.rs index ce0d5d4d24..b9e1bcc56f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -478,6 +478,10 @@ impl Builder { output_vector.push("--no-prepend-enum-name".into()); } + if self.options.fit_macro_constants { + output_vector.push("--fit-macro-constant-types".into()); + } + if self.options.array_pointers_in_arguments { output_vector.push("--use-array-pointers-in-arguments".into()); } @@ -1287,6 +1291,12 @@ impl Builder { self } + /// Whether to try to fit macro constants to types smaller than u32/i32 + pub fn fit_macro_constants(mut self, doit: bool) -> Self { + self.options.fit_macro_constants = doit; + self + } + /// Prepend the enum name to constant or newtype variants. pub fn prepend_enum_name(mut self, doit: bool) -> Self { self.options.prepend_enum_name = doit; @@ -1735,6 +1745,9 @@ struct BindgenOptions { /// Whether to detect include paths using clang_sys. detect_include_paths: bool, + /// Whether to try to fit macro constants into types smaller than u32/i32 + fit_macro_constants: bool, + /// Whether to prepend the enum name to constant or newtype variants. prepend_enum_name: bool, @@ -1905,6 +1918,7 @@ impl Default for BindgenOptions { block_extern_crate: false, enable_mangling: true, detect_include_paths: true, + fit_macro_constants: false, prepend_enum_name: true, time_phases: false, record_matches: true, diff --git a/src/options.rs b/src/options.rs index 8beac4696e..7d3e077ee8 100644 --- a/src/options.rs +++ b/src/options.rs @@ -316,6 +316,9 @@ where Arg::with_name("no-include-path-detection") .long("no-include-path-detection") .help("Do not try to detect default include paths"), + Arg::with_name("fit-macro-constant-types") + .long("fit-macro-constant-types") + .help("Try to fit macro constants into types smaller than u32/i32"), Arg::with_name("unstable-rust") .long("unstable-rust") .help("Generate unstable Rust code (deprecated; use --rust-target instead).") @@ -654,6 +657,10 @@ where builder = builder.detect_include_paths(false); } + if matches.is_present("fit-macro-constant-types") { + builder = builder.fit_macro_constants(true); + } + if matches.is_present("time-phases") { builder = builder.time_phases(true); } diff --git a/tests/expectations/tests/default-macro-constant-type-signed.rs b/tests/expectations/tests/default-macro-constant-type-signed.rs index eda3117d3e..38ebc531b3 100644 --- a/tests/expectations/tests/default-macro-constant-type-signed.rs +++ b/tests/expectations/tests/default-macro-constant-type-signed.rs @@ -10,6 +10,18 @@ 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_U16: i32 = 65535; +pub const MAX_I16: i32 = 32767; +pub const MAX_I16_Plus1: i32 = 32768; +pub const MAX_U16_Plus1: i32 = 65536; +pub const MAX_I16_Minus1: i32 = 32766; +pub const MAX_U16_Minus1: i32 = 65534; +pub const MIN_U16: i32 = 0; +pub const MIN_I16: i32 = -32768; +pub const MIN_U16_Plus1: i32 = 1; +pub const MIN_I16_Plus1: i32 = -32767; +pub const MIN_U16_Minus1: i32 = -1; +pub const MIN_I16_Minus1: i32 = -32769; pub const MAX_U32: i64 = 4294967295; pub const MAX_I32: i32 = 2147483647; pub const MAX_I32_Plus1: i64 = 2147483648; diff --git a/tests/expectations/tests/default-macro-constant-type-unsigned.rs b/tests/expectations/tests/default-macro-constant-type-unsigned.rs index 241443aa41..5571563bcd 100644 --- a/tests/expectations/tests/default-macro-constant-type-unsigned.rs +++ b/tests/expectations/tests/default-macro-constant-type-unsigned.rs @@ -10,6 +10,18 @@ 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_U16: u32 = 65535; +pub const MAX_I16: u32 = 32767; +pub const MAX_I16_Plus1: u32 = 32768; +pub const MAX_U16_Plus1: u32 = 65536; +pub const MAX_I16_Minus1: u32 = 32766; +pub const MAX_U16_Minus1: u32 = 65534; +pub const MIN_U16: u32 = 0; +pub const MIN_I16: i32 = -32768; +pub const MIN_U16_Plus1: u32 = 1; +pub const MIN_I16_Plus1: i32 = -32767; +pub const MIN_U16_Minus1: i32 = -1; +pub const MIN_I16_Minus1: i32 = -32769; pub const MAX_U32: u32 = 4294967295; pub const MAX_I32: u32 = 2147483647; pub const MAX_I32_Plus1: u32 = 2147483648; diff --git a/tests/expectations/tests/default-macro-constant-type.rs b/tests/expectations/tests/default-macro-constant-type.rs index 241443aa41..5571563bcd 100644 --- a/tests/expectations/tests/default-macro-constant-type.rs +++ b/tests/expectations/tests/default-macro-constant-type.rs @@ -10,6 +10,18 @@ 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_U16: u32 = 65535; +pub const MAX_I16: u32 = 32767; +pub const MAX_I16_Plus1: u32 = 32768; +pub const MAX_U16_Plus1: u32 = 65536; +pub const MAX_I16_Minus1: u32 = 32766; +pub const MAX_U16_Minus1: u32 = 65534; +pub const MIN_U16: u32 = 0; +pub const MIN_I16: i32 = -32768; +pub const MIN_U16_Plus1: u32 = 1; +pub const MIN_I16_Plus1: i32 = -32767; +pub const MIN_U16_Minus1: i32 = -1; +pub const MIN_I16_Minus1: i32 = -32769; pub const MAX_U32: u32 = 4294967295; pub const MAX_I32: u32 = 2147483647; pub const MAX_I32_Plus1: u32 = 2147483648; diff --git a/tests/expectations/tests/fit-macro-constant-types.rs b/tests/expectations/tests/fit-macro-constant-types.rs new file mode 100644 index 0000000000..d8d3f207c1 --- /dev/null +++ b/tests/expectations/tests/fit-macro-constant-types.rs @@ -0,0 +1,54 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +pub const N0: u8 = 0; +pub const N1: u8 = 1; +pub const N2: u8 = 2; +pub const N_1: i8 = -1; +pub const N_2: i8 = -2; +pub const MAX_U16: u16 = 65535; +pub const MAX_I16: u16 = 32767; +pub const MAX_I16_Plus1: u16 = 32768; +pub const MAX_U16_Plus1: u32 = 65536; +pub const MAX_I16_Minus1: u16 = 32766; +pub const MAX_U16_Minus1: u16 = 65534; +pub const MIN_U16: u8 = 0; +pub const MIN_I16: i16 = -32768; +pub const MIN_U16_Plus1: u8 = 1; +pub const MIN_I16_Plus1: i16 = -32767; +pub const MIN_U16_Minus1: i8 = -1; +pub const MIN_I16_Minus1: i32 = -32769; +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: u8 = 0; +pub const MIN_I32: i32 = -2147483648; +pub const MIN_U32_Plus1: u8 = 1; +pub const MIN_I32_Plus1: i32 = -2147483647; +pub const MIN_U32_Minus1: i8 = -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.h b/tests/headers/default-macro-constant-type.h index d11941b440..a863362c98 100644 --- a/tests/headers/default-macro-constant-type.h +++ b/tests/headers/default-macro-constant-type.h @@ -8,6 +8,24 @@ #define N_1 (-1LL) #define N_2 (-2LL) +#define MAX_U16 0xFFFFULL +#define MAX_I16 (0x8000ULL - 1) + +#define MAX_I16_Plus1 (MAX_I16 + 1) +#define MAX_U16_Plus1 (MAX_U16 + 1) + +#define MAX_I16_Minus1 (MAX_I16 - 1) +#define MAX_U16_Minus1 (MAX_U16 - 1) + +#define MIN_U16 0 +#define MIN_I16 (- (1ULL<<15)) + +#define MIN_U16_Plus1 (MIN_U16 + 1) +#define MIN_I16_Plus1 (MIN_I16 + 1) + +#define MIN_U16_Minus1 (MIN_U16 - 1) +#define MIN_I16_Minus1 (MIN_I16 - 1) + #define MAX_U32 0xFFFFFFFFULL #define MAX_I32 (0x80000000ULL - 1) diff --git a/tests/headers/fit-macro-constant-types.h b/tests/headers/fit-macro-constant-types.h new file mode 100644 index 0000000000..b995bfc0d4 --- /dev/null +++ b/tests/headers/fit-macro-constant-types.h @@ -0,0 +1,4 @@ +// bindgen-flags: --fit-macro-constant-types +// Test fitting macro constants into smaller integer types +// Negative values are i8, i16, i32 or i64; others are u8, u16, u32 or u64. +#include "default-macro-constant-type.h" \ No newline at end of file