diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 583f46ea93..0d8fa33c93 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -1,7 +1,7 @@ extern crate bindgen; use bindgen::callbacks::{ - DeriveInfo, IntKind, MacroParsingBehavior, ParseCallbacks, + DeriveInfo, IntKind, MacroParsingBehavior, ParseCallbacks, Token, TokenKind, }; use bindgen::{Builder, EnumVariation, Formatter}; use std::collections::HashSet; @@ -145,6 +145,48 @@ impl ParseCallbacks for MacroCallback { vec![] } } + + fn modify_macro(&self, _name: &str, tokens: &mut Vec) { + // Handle macros dealing with bit positions of the format HI:LO + if tokens.len() == 4 && tokens[2].kind == TokenKind::Punctuation { + if let Ok(colon) = std::str::from_utf8(&tokens[2].raw) { + if colon != ":" { + return; + } + let high = match std::str::from_utf8(&tokens[1].raw) { + Ok(s) => { + if let Ok(val) = s.parse::() { + val + } else { + return; + } + } + Err(_) => { + return; + } + }; + + let low = match std::str::from_utf8(&tokens[3].raw) { + Ok(s) => { + if let Ok(val) = s.parse::() { + val + } else { + return; + } + } + Err(_) => { + return; + } + }; + let value: u32 = ((high as u32) << 16) | low as u32; + tokens[1] = Token::from(( + TokenKind::Literal, + value.to_string().as_bytes(), + )); + tokens.truncate(2); + } + } + } } impl Drop for MacroCallback { diff --git a/bindgen-integration/cpp/Test.h b/bindgen-integration/cpp/Test.h index 81a921b5f8..7f71210cdd 100644 --- a/bindgen-integration/cpp/Test.h +++ b/bindgen-integration/cpp/Test.h @@ -22,6 +22,8 @@ #define TESTMACRO_STRING_EXPR ("string") #define TESTMACRO_STRING_FUNC_NON_UTF8(x) (x "ÿÿ") /* invalid UTF-8 on purpose */ +#define TESTMACRO_COLON_VALUE 1:2 + enum { MY_ANNOYING_MACRO = #define MY_ANNOYING_MACRO 1 diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 13f5bd889a..64f4926a8b 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -345,3 +345,9 @@ fn test_wrap_static_fns() { extern_bindings::wrap_as_variadic_fn2_wrapped(1, 2); } } + +#[test] +fn test_colon_define() { + let gold: u32 = (1u32 << 16) | 2; + assert_eq!(gold, bindings::TESTMACRO_COLON_VALUE); +} diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs index cd7bb9773d..f7f2f6cc9d 100644 --- a/bindgen/callbacks.rs +++ b/bindgen/callbacks.rs @@ -4,6 +4,8 @@ pub use crate::ir::analysis::DeriveTrait; pub use crate::ir::derive::CanDerive as ImplementsTrait; pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue}; pub use crate::ir::int::IntKind; +pub use cexpr::token::Kind as TokenKind; +pub use cexpr::token::Token; use std::fmt; /// An enum to allow ignoring parsing of macros. @@ -49,6 +51,9 @@ pub trait ParseCallbacks: fmt::Debug { None } + /// Modify the contents of a macro + fn modify_macro(&self, _name: &str, _tokens: &mut Vec) {} + /// The integer kind an integer macro should have, given a name and the /// value of that macro, or `None` if you want the default to be chosen. fn int_macro(&self, _name: &str, _value: i64) -> Option { diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs index 85e127fdbc..45f4ba1ba0 100644 --- a/bindgen/ir/var.rs +++ b/bindgen/ir/var.rs @@ -427,7 +427,11 @@ fn parse_macro( ) -> Option<(Vec, cexpr::expr::EvalResult)> { use cexpr::expr; - let cexpr_tokens = cursor.cexpr_tokens(); + let mut cexpr_tokens = cursor.cexpr_tokens(); + + for callbacks in &ctx.options().parse_callbacks { + callbacks.modify_macro(&cursor.spelling(), &mut cexpr_tokens); + } let parser = expr::IdentifierParser::new(ctx.parsed_macros());