summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChih-Hung Hsieh <chh@google.com>2020-08-08 16:20:47 -0700
committerEmilio Cobos Álvarez <emilio@crisal.io>2020-08-09 13:01:46 +0200
commit53290e8f3535f118bcc06c048d34740233ef7821 (patch)
tree1e347f692a9ca8c3fe7cac7384273cea8dc7b98b
parent1127561bb232fe0aa3ef48cc8404b26ed3b7116c (diff)
Add --default-macro-constant-type
* --default-macro-constant-type could be 'signed' or 'unsigned' * Its default value is 'unsigned' to use u32/u64 for C macro constants that fit into the u32/u64 ranges. * For old C libraries that use macros as int/long parameter and/or return value types, their macros are better declared as i32/i64 if the values fit the i32/i64 ranges, to be compatible with c_int/c_long types. They can use "--default-macro-constant-type signed"
-rw-r--r--src/codegen/mod.rs44
-rw-r--r--src/ir/var.rs12
-rw-r--r--src/lib.rs21
-rw-r--r--src/options.rs17
-rw-r--r--tests/expectations/tests/default-macro-constant-type-signed.rs42
-rw-r--r--tests/expectations/tests/default-macro-constant-type-unsigned.rs42
-rw-r--r--tests/expectations/tests/default-macro-constant-type.rs42
-rw-r--r--tests/headers/default-macro-constant-type-signed.h3
-rw-r--r--tests/headers/default-macro-constant-type-unsigned.h3
-rw-r--r--tests/headers/default-macro-constant-type.h34
10 files changed, 253 insertions, 7 deletions
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<Self, Self::Err> {
+ 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);