diff --git a/bindgen-tests/tests/expectations/tests/class_static_const.rs b/bindgen-tests/tests/expectations/tests/class_static_const.rs index d628239c4c..c09d181d0f 100644 --- a/bindgen-tests/tests/expectations/tests/class_static_const.rs +++ b/bindgen-tests/tests/expectations/tests/class_static_const.rs @@ -5,8 +5,8 @@ pub struct A { pub _address: u8, } pub const A_a: ::std::os::raw::c_int = 0; -pub const A_b: i32 = 63; -pub const A_c: u32 = 255; +pub const A_b: i32 = 0o77; +pub const A_c: u32 = 0xff; #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { ["Size of A"][::std::mem::size_of::() - 1usize]; diff --git a/bindgen-tests/tests/expectations/tests/constant-evaluate.rs b/bindgen-tests/tests/expectations/tests/constant-evaluate.rs index bbcf6d5450..8506729427 100644 --- a/bindgen-tests/tests/expectations/tests/constant-evaluate.rs +++ b/bindgen-tests/tests/expectations/tests/constant-evaluate.rs @@ -8,7 +8,7 @@ pub enum _bindgen_ty_1 { bar = 8, } pub type EasyToOverflow = ::std::os::raw::c_ulonglong; -pub const k: EasyToOverflow = 2147483648; +pub const k: EasyToOverflow = 0x80000000; pub const k_expr: EasyToOverflow = 1152921504606846976; pub const wow: EasyToOverflow = 2147483648; pub const BAZ: ::std::os::raw::c_longlong = 24; diff --git a/bindgen-tests/tests/expectations/tests/default-macro-constant-type-signed.rs b/bindgen-tests/tests/expectations/tests/default-macro-constant-type-signed.rs index 7fca57b6b9..ec0032fc2c 100644 --- a/bindgen-tests/tests/expectations/tests/default-macro-constant-type-signed.rs +++ b/bindgen-tests/tests/expectations/tests/default-macro-constant-type-signed.rs @@ -4,8 +4,8 @@ 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_U16: i32 = 0xffff; +pub const MAX_I16: i32 = 0x7fff; pub const MAX_I16_Plus1: i32 = 32768; pub const MAX_U16_Plus1: i32 = 65536; pub const MAX_I16_Minus1: i32 = 32766; @@ -16,8 +16,8 @@ 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_U32: i64 = 0xffffffff; +pub const MAX_I32: i32 = 0x7fffffff; pub const MAX_I32_Plus1: i64 = 2147483648; pub const MAX_U32_Plus1: i64 = 4294967296; pub const MAX_I32_Minus1: i32 = 2147483646; diff --git a/bindgen-tests/tests/expectations/tests/default-macro-constant-type-unsigned.rs b/bindgen-tests/tests/expectations/tests/default-macro-constant-type-unsigned.rs index d34d050a1a..f492b6bfc4 100644 --- a/bindgen-tests/tests/expectations/tests/default-macro-constant-type-unsigned.rs +++ b/bindgen-tests/tests/expectations/tests/default-macro-constant-type-unsigned.rs @@ -4,8 +4,8 @@ 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_U16: u32 = 0xffff; +pub const MAX_I16: u32 = 0x7fff; pub const MAX_I16_Plus1: u32 = 32768; pub const MAX_U16_Plus1: u32 = 65536; pub const MAX_I16_Minus1: u32 = 32766; @@ -16,8 +16,8 @@ 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_U32: u32 = 0xffffffff; +pub const MAX_I32: u32 = 0x7fffffff; pub const MAX_I32_Plus1: u32 = 2147483648; pub const MAX_U32_Plus1: u64 = 4294967296; pub const MAX_I32_Minus1: u32 = 2147483646; diff --git a/bindgen-tests/tests/expectations/tests/default-macro-constant-type.rs b/bindgen-tests/tests/expectations/tests/default-macro-constant-type.rs index d34d050a1a..f492b6bfc4 100644 --- a/bindgen-tests/tests/expectations/tests/default-macro-constant-type.rs +++ b/bindgen-tests/tests/expectations/tests/default-macro-constant-type.rs @@ -4,8 +4,8 @@ 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_U16: u32 = 0xffff; +pub const MAX_I16: u32 = 0x7fff; pub const MAX_I16_Plus1: u32 = 32768; pub const MAX_U16_Plus1: u32 = 65536; pub const MAX_I16_Minus1: u32 = 32766; @@ -16,8 +16,8 @@ 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_U32: u32 = 0xffffffff; +pub const MAX_I32: u32 = 0x7fffffff; pub const MAX_I32_Plus1: u32 = 2147483648; pub const MAX_U32_Plus1: u64 = 4294967296; pub const MAX_I32_Minus1: u32 = 2147483646; diff --git a/bindgen-tests/tests/expectations/tests/different_radix_literals.rs b/bindgen-tests/tests/expectations/tests/different_radix_literals.rs new file mode 100644 index 0000000000..677fd70ccc --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/different_radix_literals.rs @@ -0,0 +1,32 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const DEFINE_BIN_LITERAL: u32 = 0b10; +pub const DEFINE_NEG_BIN_LITERAL: i32 = -0b10; +pub const DEFINE_OCT_LITERAL: u32 = 0o10; +pub const DEFINE_NEG_OCT_LITERAL: i32 = -0o10; +pub const DEFINE_HEX_LITERAL: u32 = 0x10; +pub const DEFINE_NEG_HEX_LITERAL: i32 = -0x10; +pub const DEFINE_DEC_LITERAL: u32 = 10; +pub const DEFINE_NEG_DEC_LITERAL: i32 = -10; +pub const CONST_INT_BIN_LITERAL: ::std::os::raw::c_int = 0b10; +pub const CONST_INT_NEG_BIN_LITERAL: ::std::os::raw::c_int = -0b10; +pub const CONST_INT_OCT_LITERAL: ::std::os::raw::c_int = 0o10; +pub const CONST_INT_NEG_OCT_LITERAL: ::std::os::raw::c_int = -0o10; +pub const CONST_INT_HEX_LITERAL: ::std::os::raw::c_int = 0x10; +pub const CONST_INT_NEG_HEX_LITERAL: ::std::os::raw::c_int = -0x10; +pub const CONST_INT_DEC_LITERAL: ::std::os::raw::c_int = 10; +pub const CONST_INT_NEG_DEC_LITERAL: ::std::os::raw::c_int = -10; +pub const MultiRadixLiteral_ENUM_BIN_LITERAL: MultiRadixLiteral = 0b10; +pub const MultiRadixLiteral_ENUM_NEG_BIN_LITERAL: MultiRadixLiteral = -0b10; +pub const MultiRadixLiteral_ENUM_OCT_LITERAL: MultiRadixLiteral = 0o10; +pub const MultiRadixLiteral_ENUM_NEG_OCT_LITERAL: MultiRadixLiteral = -0o10; +pub const MultiRadixLiteral_ENUM_HEX_LITERAL: MultiRadixLiteral = 0x10; +pub const MultiRadixLiteral_ENUM_NEG_HEX_LITERAL: MultiRadixLiteral = -0x10; +pub const MultiRadixLiteral_ENUM_DEC_LITERAL: MultiRadixLiteral = 10; +pub const MultiRadixLiteral_ENUM_NEG_DEC_LITERAL: MultiRadixLiteral = -10; +pub type MultiRadixLiteral = ::std::os::raw::c_int; +pub const MIN_I64_BIN: ::std::os::raw::c_longlong = -0b1000000000000000000000000000000000000000000000000000000000000000; +pub const MIN_I64_OCT: ::std::os::raw::c_longlong = -0o1000000000000000000000; +pub const MIN_I64_DEC: ::std::os::raw::c_longlong = -9223372036854775808; +pub const MIN_I64_HEX: ::std::os::raw::c_longlong = -0x8000000000000000; +pub const BIG_B_BIN: ::std::os::raw::c_int = 0b1; +pub const BIG_X_HEX: ::std::os::raw::c_int = 0xf; diff --git a/bindgen-tests/tests/expectations/tests/fit-macro-constant-types-signed.rs b/bindgen-tests/tests/expectations/tests/fit-macro-constant-types-signed.rs index d4ad5e0fcc..9d3588473b 100644 --- a/bindgen-tests/tests/expectations/tests/fit-macro-constant-types-signed.rs +++ b/bindgen-tests/tests/expectations/tests/fit-macro-constant-types-signed.rs @@ -4,8 +4,8 @@ pub const N1: i8 = 1; pub const N2: i8 = 2; pub const N_1: i8 = -1; pub const N_2: i8 = -2; -pub const MAX_U16: i32 = 65535; -pub const MAX_I16: i16 = 32767; +pub const MAX_U16: i32 = 0xffff; +pub const MAX_I16: i16 = 0x7fff; pub const MAX_I16_Plus1: i32 = 32768; pub const MAX_U16_Plus1: i32 = 65536; pub const MAX_I16_Minus1: i16 = 32766; @@ -16,8 +16,8 @@ pub const MIN_U16_Plus1: i8 = 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: i64 = 4294967295; -pub const MAX_I32: i32 = 2147483647; +pub const MAX_U32: i64 = 0xffffffff; +pub const MAX_I32: i32 = 0x7fffffff; pub const MAX_I32_Plus1: i64 = 2147483648; pub const MAX_U32_Plus1: i64 = 4294967296; pub const MAX_I32_Minus1: i32 = 2147483646; diff --git a/bindgen-tests/tests/expectations/tests/fit-macro-constant-types.rs b/bindgen-tests/tests/expectations/tests/fit-macro-constant-types.rs index 5542a645da..0c8d33c493 100644 --- a/bindgen-tests/tests/expectations/tests/fit-macro-constant-types.rs +++ b/bindgen-tests/tests/expectations/tests/fit-macro-constant-types.rs @@ -4,8 +4,8 @@ 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_U16: u16 = 0xffff; +pub const MAX_I16: u16 = 0x7fff; pub const MAX_I16_Plus1: u16 = 32768; pub const MAX_U16_Plus1: u32 = 65536; pub const MAX_I16_Minus1: u16 = 32766; @@ -16,8 +16,8 @@ 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_U32: u32 = 0xffffffff; +pub const MAX_I32: u32 = 0x7fffffff; pub const MAX_I32_Plus1: u32 = 2147483648; pub const MAX_U32_Plus1: u64 = 4294967296; pub const MAX_I32_Minus1: u32 = 2147483646; diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs index 7dd23241e9..6e79ba6d0d 100644 --- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs +++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs @@ -146,27 +146,27 @@ where } } pub const JSVAL_TAG_SHIFT: u32 = 47; -pub const JSVAL_PAYLOAD_MASK: u64 = 140737488355327; -pub const JSVAL_TAG_MASK: i64 = -140737488355328; +pub const JSVAL_PAYLOAD_MASK: u64 = 0x7fffffffffff; +pub const JSVAL_TAG_MASK: i64 = -0x800000000000; #[repr(u8)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSValueType { - JSVAL_TYPE_DOUBLE = 0, - JSVAL_TYPE_INT32 = 1, - JSVAL_TYPE_UNDEFINED = 2, - JSVAL_TYPE_BOOLEAN = 3, - JSVAL_TYPE_MAGIC = 4, - JSVAL_TYPE_STRING = 5, - JSVAL_TYPE_SYMBOL = 6, - JSVAL_TYPE_NULL = 7, - JSVAL_TYPE_OBJECT = 8, - JSVAL_TYPE_UNKNOWN = 32, - JSVAL_TYPE_MISSING = 33, + JSVAL_TYPE_DOUBLE = 0x0, + JSVAL_TYPE_INT32 = 0x1, + JSVAL_TYPE_UNDEFINED = 0x2, + JSVAL_TYPE_BOOLEAN = 0x3, + JSVAL_TYPE_MAGIC = 0x4, + JSVAL_TYPE_STRING = 0x5, + JSVAL_TYPE_SYMBOL = 0x6, + JSVAL_TYPE_NULL = 0x7, + JSVAL_TYPE_OBJECT = 0x8, + JSVAL_TYPE_UNKNOWN = 0x20, + JSVAL_TYPE_MISSING = 0x21, } #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSValueTag { - JSVAL_TAG_MAX_DOUBLE = 131056, + JSVAL_TAG_MAX_DOUBLE = 0x1fff0, JSVAL_TAG_INT32 = 131057, JSVAL_TAG_UNDEFINED = 131058, JSVAL_TAG_STRING = 131061, @@ -179,7 +179,7 @@ pub enum JSValueTag { #[repr(u64)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum JSValueShiftedTag { - JSVAL_SHIFTED_TAG_MAX_DOUBLE = 18444492278190833663, + JSVAL_SHIFTED_TAG_MAX_DOUBLE = 0xfff80000ffffffff, JSVAL_SHIFTED_TAG_INT32 = 18444633011384221696, JSVAL_SHIFTED_TAG_UNDEFINED = 18444773748872577024, JSVAL_SHIFTED_TAG_STRING = 18445195961337643008, diff --git a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs index 4a62ddbea3..c28ef0f263 100644 --- a/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs +++ b/bindgen-tests/tests/expectations/tests/layout_eth_conf.rs @@ -87,9 +87,9 @@ where } } } -pub const ETH_MQ_RX_RSS_FLAG: u32 = 1; -pub const ETH_MQ_RX_DCB_FLAG: u32 = 2; -pub const ETH_MQ_RX_VMDQ_FLAG: u32 = 4; +pub const ETH_MQ_RX_RSS_FLAG: u32 = 0x1; +pub const ETH_MQ_RX_DCB_FLAG: u32 = 0x2; +pub const ETH_MQ_RX_VMDQ_FLAG: u32 = 0x4; pub const ETH_VMDQ_MAX_VLAN_FILTERS: u32 = 64; pub const ETH_DCB_NUM_USER_PRIORITIES: u32 = 8; pub const ETH_VMDQ_DCB_NUM_QUEUES: u32 = 128; diff --git a/bindgen-tests/tests/expectations/tests/overflowed_enum.rs b/bindgen-tests/tests/expectations/tests/overflowed_enum.rs index 2c67ba6903..24f3057257 100644 --- a/bindgen-tests/tests/expectations/tests/overflowed_enum.rs +++ b/bindgen-tests/tests/expectations/tests/overflowed_enum.rs @@ -2,9 +2,9 @@ #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum Foo { - BAP_ARM = 9698489, - BAP_X86 = 11960045, - BAP_X86_64 = 3128633167, + BAP_ARM = 0x93fcb9, + BAP_X86 = 0xb67eed, + BAP_X86_64 = 0xba7b274f, } #[repr(u16)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/bindgen-tests/tests/expectations/tests/prepend-enum-constified-variant.rs b/bindgen-tests/tests/expectations/tests/prepend-enum-constified-variant.rs index ff49d684f1..4250e1e1f8 100644 --- a/bindgen-tests/tests/expectations/tests/prepend-enum-constified-variant.rs +++ b/bindgen-tests/tests/expectations/tests/prepend-enum-constified-variant.rs @@ -5,5 +5,5 @@ impl AVCodecID { #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum AVCodecID { - AV_CODEC_ID_FIRST_UNKNOWN = 98304, + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, } diff --git a/bindgen-tests/tests/expectations/tests/short-enums.rs b/bindgen-tests/tests/expectations/tests/short-enums.rs index 493bb5b419..9295f5b715 100644 --- a/bindgen-tests/tests/expectations/tests/short-enums.rs +++ b/bindgen-tests/tests/expectations/tests/short-enums.rs @@ -2,15 +2,15 @@ #[repr(u8)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum one_byte_t { - SOME_VALUE = 1, + SOME_VALUE = 0x1, } #[repr(u16)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum two_byte_t { - SOME_OTHER_VALUE = 256, + SOME_OTHER_VALUE = 0x100, } #[repr(u32)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum four_byte_t { - SOME_BIGGER_VALUE = 16777216, + SOME_BIGGER_VALUE = 0x1000000, } diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index bafcad8a7e..4e054d21aa 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -40,7 +40,7 @@ unsafe extern "C" { arg: *const *const ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -pub const foo_BAR: foo = 0; +pub const foo_BAR: foo = 0x0; pub type foo = ::std::os::raw::c_uint; unsafe extern "C" { #[link_name = "takes_enum__extern"] diff --git a/bindgen-tests/tests/headers/different_radix_literals.hpp b/bindgen-tests/tests/headers/different_radix_literals.hpp new file mode 100644 index 0000000000..71d8e7c2c2 --- /dev/null +++ b/bindgen-tests/tests/headers/different_radix_literals.hpp @@ -0,0 +1,55 @@ +// bindgen-flags: -- -std=c++14 +// (C23 is not available in clang 9.0, but C++14 supports the same literals) + +// Binary integer literals (C23) - 0b10 is 2 in decimal + +#define DEFINE_BIN_LITERAL 0b10 +#define DEFINE_NEG_BIN_LITERAL -0b10 +const int CONST_INT_BIN_LITERAL = 0b10; +const int CONST_INT_NEG_BIN_LITERAL = -0b10; + +// Octal integer literals - 010 is 8 in decimal + +#define DEFINE_OCT_LITERAL 010 +#define DEFINE_NEG_OCT_LITERAL -010 +const int CONST_INT_OCT_LITERAL = 010; +const int CONST_INT_NEG_OCT_LITERAL = -010; + +// Hexadecimal integer literals - 0x10 is 16 in decimal + +#define DEFINE_HEX_LITERAL 0x10 +#define DEFINE_NEG_HEX_LITERAL -0x10 +const int CONST_INT_HEX_LITERAL = 0x10; +const int CONST_INT_NEG_HEX_LITERAL = -0x10; + +// Default decimal integer literals - 10 is 10 in decimal + +#define DEFINE_DEC_LITERAL 10 +#define DEFINE_NEG_DEC_LITERAL -10 +const int CONST_INT_DEC_LITERAL = 10; +const int CONST_INT_NEG_DEC_LITERAL = -10; + +// Enums with binary, octal, and hexadecimal integer literals + +enum MultiRadixLiteral { + ENUM_BIN_LITERAL = 0b10, + ENUM_NEG_BIN_LITERAL = -0b10, + ENUM_OCT_LITERAL = 010, + ENUM_NEG_OCT_LITERAL = -010, + ENUM_HEX_LITERAL = 0x10, + ENUM_NEG_HEX_LITERAL = -0x10, + ENUM_DEC_LITERAL = 10, + ENUM_NEG_DEC_LITERAL = -10, +}; + +// Edge cases: minimum i64s + +const long long MIN_I64_BIN = -0b1000000000000000000000000000000000000000000000000000000000000000; +const long long MIN_I64_OCT = -01000000000000000000000; +const long long MIN_I64_DEC = -9223372036854775808; +const long long MIN_I64_HEX = -0x8000000000000000; + +// Big B or big X + +const int BIG_B_BIN = 0B1; +const int BIG_X_HEX = 0XF; diff --git a/bindgen/clang.rs b/bindgen/clang.rs index e52fed0d4a..8afbf44b27 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -5,6 +5,7 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::ir::context::BindgenContext; +use crate::ir::var::LiteralRadix; use clang_sys::*; use std::cmp; @@ -973,6 +974,20 @@ impl Cursor { pub(crate) fn is_inline_namespace(&self) -> bool { unsafe { clang_Cursor_isInlineNamespace(self.x) != 0 } } + + /// Obtain the number base (radix) of a literal definition corresponding to the cursor. + /// + /// Returns `None` if unable to infer a base. + pub(crate) fn get_literal_radix(&self) -> Option { + self.cexpr_tokens() + .iter() + .filter(|cexpr_token| { + cexpr_token.kind == cexpr::token::Kind::Literal + }) + .find_map(|lit_tok| { + LiteralRadix::from_literal_token_raw(&lit_tok.raw) + }) + } } /// A struct that owns the tokenizer result from a given cursor. diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs index 82172f3488..2915d6541b 100644 --- a/bindgen/codegen/helpers.rs +++ b/bindgen/codegen/helpers.rs @@ -139,6 +139,7 @@ pub(crate) mod ast_ty { use crate::ir::function::FunctionSig; use crate::ir::layout::Layout; use crate::ir::ty::{FloatKind, IntKind}; + use crate::ir::var::LiteralRadix; use crate::RustTarget; use proc_macro2::TokenStream; use std::str::FromStr; @@ -291,16 +292,70 @@ pub(crate) mod ast_ty { } } - pub(crate) fn int_expr(val: i64) -> TokenStream { + pub(crate) fn int_expr( + val: i64, + radix: Option<&LiteralRadix>, + ) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. - let val = proc_macro2::Literal::i64_unsuffixed(val); - quote!(#val) + let sign = if val.is_negative() { "-" } else { "" }; + if let Some(radix) = radix { + match radix { + LiteralRadix::Decimal => { + let val = proc_macro2::Literal::i64_unsuffixed(val); + quote!(#val) + } + LiteralRadix::Binary => { + let val = val.unsigned_abs(); + let val = format!("{sign}0b{val:b}"); + TokenStream::from_str(val.as_str()).unwrap() + } + LiteralRadix::Octal => { + let val = val.unsigned_abs(); + let val = format!("{sign}0o{val:o}"); + TokenStream::from_str(val.as_str()).unwrap() + } + LiteralRadix::Hexadecimal => { + let val = val.unsigned_abs(); + let val = format!("{sign}0x{val:x}"); + TokenStream::from_str(val.as_str()).unwrap() + } + } + } else { + // same as for Decimal + let val = proc_macro2::Literal::i64_unsuffixed(val); + quote!(#val) + } } - pub(crate) fn uint_expr(val: u64) -> TokenStream { + pub(crate) fn uint_expr( + val: u64, + radix: Option<&LiteralRadix>, + ) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. - let val = proc_macro2::Literal::u64_unsuffixed(val); - quote!(#val) + if let Some(radix) = radix { + match radix { + LiteralRadix::Decimal => { + let val = proc_macro2::Literal::u64_unsuffixed(val); + quote!(#val) + } + LiteralRadix::Binary => { + let val = format!("0b{val:b}"); + TokenStream::from_str(val.as_str()).unwrap() + } + LiteralRadix::Octal => { + let val = format!("0o{val:o}"); + TokenStream::from_str(val.as_str()).unwrap() + } + LiteralRadix::Hexadecimal => { + let val = format!("0x{val:x}"); + TokenStream::from_str(val.as_str()).unwrap() + } + } + } else { + // same as for Decimal + let val = proc_macro2::Literal::u64_unsuffixed(val); + quote!(#val) + } } pub(crate) fn cstr_expr(mut string: String) -> TokenStream { diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 433fc85f01..5d2cb47fb3 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -692,6 +692,7 @@ impl CodeGenerator for Var { }); } VarType::Int(val) => { + let radix = self.radix(); let int_kind = var_ty .into_resolver() .through_type_aliases() @@ -701,9 +702,9 @@ impl CodeGenerator for Var { .as_integer() .unwrap(); let val = if int_kind.is_signed() { - helpers::ast_ty::int_expr(val) + helpers::ast_ty::int_expr(val, radix) } else { - helpers::ast_ty::uint_expr(val as _) + helpers::ast_ty::uint_expr(val as _, radix) }; result.push(quote! { #(#attrs)* @@ -2438,7 +2439,7 @@ impl CodeGenerator for CompInfo { if let Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. - let explicit = helpers::ast_ty::int_expr(explicit as i64); + let explicit = helpers::ast_ty::int_expr(explicit as i64, None); attributes.push(quote! { #[repr(align(#explicit))] }); @@ -3384,11 +3385,15 @@ impl EnumBuilder { let is_rust_enum = self.is_rust_enum(); let expr = match variant.val() { EnumVariantValue::Boolean(v) if is_rust_enum => { - helpers::ast_ty::uint_expr(u64::from(v)) + helpers::ast_ty::uint_expr(u64::from(v), None) } EnumVariantValue::Boolean(v) => quote!(#v), - EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), - EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), + EnumVariantValue::Signed(v) => { + helpers::ast_ty::int_expr(v, variant.radix()) + } + EnumVariantValue::Unsigned(v) => { + helpers::ast_ty::uint_expr(v, variant.radix()) + } }; match self.kind { diff --git a/bindgen/ir/enum_ty.rs b/bindgen/ir/enum_ty.rs index 9b08da3bce..f97ab02657 100644 --- a/bindgen/ir/enum_ty.rs +++ b/bindgen/ir/enum_ty.rs @@ -6,6 +6,7 @@ use super::item::Item; use super::ty::{Type, TypeKind}; use crate::clang; use crate::ir::annotations::Annotations; +use crate::ir::var::LiteralRadix; use crate::parse::ParseError; use crate::regex_set::RegexSet; @@ -101,8 +102,10 @@ impl Enum { } else { cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) }; + if let Some(val) = value { let name = cursor.spelling(); + let radix = cursor.get_literal_radix(); let annotations = Annotations::new(&cursor); let custom_behavior = ctx .options() @@ -142,6 +145,7 @@ impl Enum { comment, val, custom_behavior, + radix, )); } } @@ -254,6 +258,9 @@ pub(crate) struct EnumVariant { /// The custom behavior this variant may have, if any. custom_behavior: Option, + + /// The radix of the literal value of the variant. + radix: Option, } /// A constant value assigned to an enumeration variant. @@ -277,6 +284,7 @@ impl EnumVariant { comment: Option, val: EnumVariantValue, custom_behavior: Option, + radix: Option, ) -> Self { EnumVariant { name, @@ -284,6 +292,7 @@ impl EnumVariant { comment, val, custom_behavior, + radix, } } @@ -302,6 +311,11 @@ impl EnumVariant { self.val } + /// Get this variant's radix. + pub(crate) fn radix(&self) -> Option<&LiteralRadix> { + self.radix.as_ref() + } + /// Get this variant's documentation. pub(crate) fn comment(&self) -> Option<&str> { self.comment.as_deref() diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs index 45f4ba1ba0..6dea0d4be9 100644 --- a/bindgen/ir/var.rs +++ b/bindgen/ir/var.rs @@ -30,6 +30,42 @@ pub(crate) enum VarType { String(Vec), } +/// Integer literal's radix. +#[derive(Debug)] +pub(crate) enum LiteralRadix { + /// Binary (base 2). + Binary, + /// Octal (base 8). + Octal, + /// Decimal (base 10). + Decimal, + /// Hexadecimal (base 16). + Hexadecimal, +} + +impl LiteralRadix { + /// Obtain the number base of a bytestring corresponding to an existing literal + /// definition. + /// + /// Returns `None` if unable to infer a base. + pub(crate) fn from_literal_token_raw(lit_tok_raw: &[u8]) -> Option { + if lit_tok_raw.len() > 1 { + match lit_tok_raw[0] { + b'0' => match lit_tok_raw[1] { + b'x' | b'X' => Some(Self::Hexadecimal), + b'b' | b'B' => Some(Self::Binary), + b'0'..=b'7' => Some(Self::Octal), + _ => None, + }, + b'1'..=b'9' => Some(Self::Decimal), + _ => None, + } + } else { + Some(Self::Decimal) + } + } +} + /// A `Var` is our intermediate representation of a variable. #[derive(Debug)] pub(crate) struct Var { @@ -45,6 +81,8 @@ pub(crate) struct Var { val: Option, /// Whether this variable is const. is_const: bool, + /// The radix of the variable, if integer. + radix: Option, } impl Var { @@ -56,6 +94,7 @@ impl Var { ty: TypeId, val: Option, is_const: bool, + radix: Option, ) -> Var { assert!(!name.is_empty()); Var { @@ -65,9 +104,15 @@ impl Var { ty, val, is_const, + radix, } } + /// The radix of this integer variable, if any. + pub(crate) fn radix(&self) -> Option<&LiteralRadix> { + self.radix.as_ref() + } + /// Is this variable `const` qualified? pub(crate) fn is_const(&self) -> bool { self.is_const @@ -223,11 +268,13 @@ impl ClangSubItemParser for Var { // enforce utf8 there, so we should have already panicked at // this point. let name = String::from_utf8(id).unwrap(); - let (type_kind, val) = match value { + let (type_kind, val, radix) = match value { EvalResult::Invalid => return Err(ParseError::Continue), - EvalResult::Float(f) => { - (TypeKind::Float(FloatKind::Double), VarType::Float(f)) - } + EvalResult::Float(f) => ( + TypeKind::Float(FloatKind::Double), + VarType::Float(f), + None, + ), EvalResult::Char(c) => { let c = match c { CChar::Char(c) => { @@ -237,7 +284,7 @@ impl ClangSubItemParser for Var { CChar::Raw(c) => u8::try_from(c).unwrap(), }; - (TypeKind::Int(IntKind::U8), VarType::Char(c)) + (TypeKind::Int(IntKind::U8), VarType::Char(c), None) } EvalResult::Str(val) => { let char_ty = Item::builtin_type( @@ -248,7 +295,7 @@ impl ClangSubItemParser for Var { for callbacks in &ctx.options().parse_callbacks { callbacks.str_macro(&name, &val); } - (TypeKind::Pointer(char_ty), VarType::String(val)) + (TypeKind::Pointer(char_ty), VarType::String(val), None) } EvalResult::Int(Wrapping(value)) => { let kind = ctx @@ -258,14 +305,16 @@ impl ClangSubItemParser for Var { default_macro_constant_type(ctx, value) }); - (TypeKind::Int(kind), VarType::Int(value)) + let radix = cursor.get_literal_radix(); + + (TypeKind::Int(kind), VarType::Int(value), radix) } }; let ty = Item::builtin_type(type_kind, true, ctx); Ok(ParseResult::New( - Var::new(name, None, None, ty, Some(val), true), + Var::new(name, None, None, ty, Some(val), true, radix), Some(cursor), )) } @@ -334,39 +383,51 @@ impl ClangSubItemParser for Var { // TODO: Strings, though the lookup is a bit more hard (we need // to look at the canonical type of the pointee too, and check // is char, u8, or i8 I guess). - let value = if is_integer { + let (value, radix) = if is_integer { let TypeKind::Int(kind) = *canonical_ty.unwrap().kind() else { unreachable!() }; let mut val = cursor.evaluate().and_then(|v| v.as_int()); + let radix = cursor.get_literal_radix(); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { val = get_integer_literal_from_cursor(&cursor); } - val.map(|val| { - if kind == IntKind::Bool { - VarType::Bool(val != 0) - } else { - VarType::Int(val) - } - }) + ( + val.map(|val| { + if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + } + }), + radix, + ) } else if is_float { - cursor - .evaluate() - .and_then(|v| v.as_double()) - .map(VarType::Float) + ( + cursor + .evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float), + None, + ) } else { - cursor - .evaluate() - .and_then(|v| v.as_literal_string()) - .map(VarType::String) + ( + cursor + .evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String), + None, + ) }; let mangling = cursor_mangling(ctx, &cursor); - let var = - Var::new(name, mangling, link_name, ty, value, is_const); + let var = Var::new( + name, mangling, link_name, ty, value, is_const, radix, + ); Ok(ParseResult::New(var, Some(cursor))) }