Skip to content

Commit

Permalink
Add option to fit macro consts into smaller types
Browse files Browse the repository at this point in the history
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 rust-lang#1945
  • Loading branch information
Skelebot authored and LoganBarnett committed Dec 2, 2023
1 parent e31ec19 commit 09607ee
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 11 deletions.
54 changes: 43 additions & 11 deletions src/ir/var.rs
Expand Up @@ -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
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions src/options.rs
Expand Up @@ -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).")
Expand Down Expand Up @@ -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);
}
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/tests/default-macro-constant-type-signed.rs
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/tests/default-macro-constant-type-unsigned.rs
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/tests/default-macro-constant-type.rs
Expand Up @@ -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;
Expand Down
54 changes: 54 additions & 0 deletions 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;
}
18 changes: 18 additions & 0 deletions tests/headers/default-macro-constant-type.h
Expand Up @@ -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)

Expand Down
4 changes: 4 additions & 0 deletions 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"

0 comments on commit 09607ee

Please sign in to comment.