summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-11-16 15:12:52 -0600
committerGitHub <noreply@github.com>2016-11-16 15:12:52 -0600
commite74acce09bc0f643a0084334f56837bb09f9cf42 (patch)
tree784ee1e899accea78f75b7ba87bc58b5e4b6a84d
parentc800ad46a7b7713ed16f20d85479a608faf63c50 (diff)
parent19d36d436ec8674604ea53a249fc8a952eab2d33 (diff)
Auto merge of #260 - emilio:macro-str, r=fitzgen
Constant variable improvements. Fixes #256. r? @fitzgen
-rw-r--r--libbindgen/build.rs7
-rw-r--r--libbindgen/src/clang.rs78
-rw-r--r--libbindgen/src/clangll.rs29
-rw-r--r--libbindgen/src/codegen/helpers.rs33
-rw-r--r--libbindgen/src/codegen/mod.rs43
-rw-r--r--libbindgen/src/ir/context.rs5
-rw-r--r--libbindgen/src/ir/item.rs6
-rw-r--r--libbindgen/src/ir/ty.rs12
-rw-r--r--libbindgen/src/ir/var.rs98
-rw-r--r--libbindgen/tests/expectations/tests/constant-evaluate.rs15
-rw-r--r--libbindgen/tests/expectations/tests/macro_const.rs12
-rw-r--r--libbindgen/tests/expectations/tests/msvc-no-usr.rs19
-rw-r--r--libbindgen/tests/expectations/tests/type_alias_partial_template_especialization.rs (renamed from tests/expectations/tests/type_alias_partial_template_especialization.rs)0
-rw-r--r--libbindgen/tests/expectations/tests/type_alias_template_specialized.rs (renamed from tests/expectations/tests/type_alias_template_specialized.rs)0
-rw-r--r--libbindgen/tests/headers/constant-evaluate.h11
-rw-r--r--libbindgen/tests/headers/macro_const.h7
-rw-r--r--libbindgen/tests/headers/msvc-no-usr.hpp8
-rw-r--r--libbindgen/tests/headers/type_alias_partial_template_especialization.hpp (renamed from tests/headers/type_alias_partial_template_especialization.hpp)0
-rw-r--r--libbindgen/tests/headers/type_alias_template_specialized.hpp (renamed from tests/headers/type_alias_template_specialized.hpp)0
-rw-r--r--libbindgen/tests/tests.rs60
20 files changed, 384 insertions, 59 deletions
diff --git a/libbindgen/build.rs b/libbindgen/build.rs
index 228a7f22..98bb76a9 100644
--- a/libbindgen/build.rs
+++ b/libbindgen/build.rs
@@ -38,13 +38,14 @@ mod testgen {
.replace(|c| !char::is_alphanumeric(c), "_")
.replace("__", "_")
.to_lowercase();
- let _ = writeln!(dst, "test_header!(header_{}, {:?});",
- func, entry.path());
+ writeln!(dst, "test_header!(header_{}, {:?});",
+ func, entry.path()).unwrap();
}
_ => {}
}
}
- let _ = dst.flush();
+
+ dst.flush().unwrap();
}
}
diff --git a/libbindgen/src/clang.rs b/libbindgen/src/clang.rs
index d10457b3..637823ea 100644
--- a/libbindgen/src/clang.rs
+++ b/libbindgen/src/clang.rs
@@ -264,7 +264,7 @@ impl Cursor {
/// Given that this cursor's referent is reference type, get the cursor
/// pointing to the referenced type.
- pub fn referenced(&self) -> Option<Cursor> {
+ pub fn referenced(&self) -> Option<Cursor> {
unsafe {
let ret = Cursor {
x: clang_getCursorReferenced(self.x),
@@ -475,6 +475,11 @@ impl Cursor {
pub fn is_virtual_base(&self) -> bool {
unsafe { clang_isVirtualBase(self.x) != 0 }
}
+
+ /// Try to evaluate this cursor.
+ pub fn evaluate(&self) -> EvalResult {
+ EvalResult::new(*self)
+ }
}
extern "C" fn visit_children<Visitor>(cur: CXCursor,
@@ -933,7 +938,9 @@ impl Into<String> for CXString {
}
unsafe {
let c_str = CStr::from_ptr(clang_getCString(self) as *const _);
- c_str.to_string_lossy().into_owned()
+ let ret = c_str.to_string_lossy().into_owned();
+ clang_disposeString(self);
+ ret
}
}
}
@@ -1259,3 +1266,70 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult {
pub fn extract_clang_version() -> String {
unsafe { clang_getClangVersion().into() }
}
+
+/// A wrapper for the result of evaluating an expression.
+#[derive(Debug)]
+pub struct EvalResult {
+ x: CXEvalResult,
+}
+
+#[cfg(feature = "llvm_stable")]
+impl EvalResult {
+ /// Create a dummy EvalResult.
+ pub fn new(_: Cursor) -> Self {
+ EvalResult {
+ x: ptr::null_mut(),
+ }
+ }
+
+ /// Not useful in llvm 3.8.
+ pub fn as_double(&self) -> Option<f64> {
+ None
+ }
+
+ /// Not useful in llvm 3.8.
+ pub fn as_int(&self) -> Option<i32> {
+ None
+ }
+}
+
+#[cfg(not(feature = "llvm_stable"))]
+impl EvalResult {
+ /// Evaluate `cursor` and return the result.
+ pub fn new(cursor: Cursor) -> Self {
+ EvalResult {
+ x: unsafe { clang_Cursor_Evaluate(cursor.x) },
+ }
+ }
+
+ fn kind(&self) -> Enum_CXEvalResultKind {
+ unsafe { clang_EvalResult_getKind(self.x) }
+ }
+
+ /// Try to get back the result as a double.
+ pub fn as_double(&self) -> Option<f64> {
+ match self.kind() {
+ CXEval_Float => {
+ Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
+ }
+ _ => None,
+ }
+ }
+
+ /// Try to get back the result as an integer.
+ pub fn as_int(&self) -> Option<i32> {
+ match self.kind() {
+ CXEval_Int => {
+ Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32)
+ }
+ _ => None,
+ }
+ }
+}
+
+#[cfg(not(feature = "llvm_stable"))]
+impl Drop for EvalResult {
+ fn drop(&mut self) {
+ unsafe { clang_EvalResult_dispose(self.x) };
+ }
+}
diff --git a/libbindgen/src/clangll.rs b/libbindgen/src/clangll.rs
index b9743117..e37baf25 100644
--- a/libbindgen/src/clangll.rs
+++ b/libbindgen/src/clangll.rs
@@ -7,7 +7,22 @@
#![allow(non_upper_case_globals)]
#![cfg_attr(rustfmt, rustfmt_skip)]
-use ::std::os::raw::{ c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong, c_void};
+use ::std::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong, c_void};
+
+#[cfg(not(feature = "llvm_stable"))]
+use std::os::raw::c_double;
+
+
+pub type CXEvalResult = *mut c_void;
+pub type Enum_CXEvalResultKind = c_uint;
+
+pub const CXEval_Int: c_uint = 1;
+pub const CXEval_Float: c_uint = 2;
+pub const CXEval_ObjCStrLiteral: c_uint = 3;
+pub const CXEval_StrLiteral: c_uint = 4;
+pub const CXEval_CFStr: c_uint = 5;
+pub const CXEval_Other: c_uint = 6;
+pub const CXEval_UnExposed: c_uint = 0;
pub type ptrdiff_t = c_long;
pub type size_t = c_ulong;
@@ -1436,4 +1451,16 @@ extern "C" {
offset: *mut c_uint);
pub fn clang_indexLoc_getCXSourceLocation(loc: CXIdxLoc) ->
CXSourceLocation;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_Cursor_Evaluate(C: CXCursor) -> CXEvalResult;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_EvalResult_getKind(E: CXEvalResult) -> Enum_CXEvalResultKind;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_EvalResult_getAsInt(E: CXEvalResult) -> c_int;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_EvalResult_getAsDouble(E: CXEvalResult) -> c_double;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_EvalResult_getAsStr(E: CXEvalResult) -> *const c_char;
+ #[cfg(not(feature="llvm_stable"))]
+ pub fn clang_EvalResult_dispose(E: CXEvalResult);
}
diff --git a/libbindgen/src/codegen/helpers.rs b/libbindgen/src/codegen/helpers.rs
index 6e5a6f0e..8c3d3cea 100644
--- a/libbindgen/src/codegen/helpers.rs
+++ b/libbindgen/src/codegen/helpers.rs
@@ -132,4 +132,37 @@ pub mod ast_ty {
expr.int(val)
}
}
+
+ pub fn byte_array_expr(bytes: &[u8]) -> P<ast::Expr> {
+ let mut vec = Vec::with_capacity(bytes.len() + 1);
+ for byte in bytes {
+ vec.push(int_expr(*byte as i64));
+ }
+ vec.push(int_expr(0));
+
+ let kind = ast::ExprKind::Vec(vec);
+
+ aster::AstBuilder::new().expr().build_expr_kind(kind)
+ }
+
+ pub fn cstr_expr(mut string: String) -> P<ast::Expr> {
+ string.push('\0');
+ aster::AstBuilder::new()
+ .expr()
+ .build_lit(aster::AstBuilder::new().lit().byte_str(string))
+ }
+
+ pub fn float_expr(f: f64) -> P<ast::Expr> {
+ use aster::str::ToInternedString;
+ let mut string = f.to_string();
+
+ // So it gets properly recognised as a floating point constant.
+ if !string.contains('.') {
+ string.push('.');
+ }
+
+ let interned_str = string.as_str().to_interned_string();
+ let kind = ast::LitKind::FloatUnsuffixed(interned_str);
+ aster::AstBuilder::new().expr().lit().build_lit(kind)
+ }
}
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs
index 99ec56f4..ceb023f7 100644
--- a/libbindgen/src/codegen/mod.rs
+++ b/libbindgen/src/codegen/mod.rs
@@ -304,6 +304,7 @@ impl CodeGenerator for Var {
ctx: &BindgenContext,
result: &mut CodegenResult,
item: &Item) {
+ use ir::var::VarType;
debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
let canonical_name = item.canonical_name(ctx);
@@ -320,10 +321,44 @@ impl CodeGenerator for Var {
.item()
.pub_()
.const_(canonical_name)
- .expr()
- .build(helpers::ast_ty::int_expr(val))
- .build(ty);
- result.push(const_item)
+ .expr();
+ let item = match *val {
+ VarType::Int(val) => {
+ const_item.build(helpers::ast_ty::int_expr(val))
+ .build(ty)
+ }
+ VarType::String(ref bytes) => {
+ // Account the trailing zero.
+ //
+ // TODO: Here we ignore the type we just made up, probably
+ // we should refactor how the variable type and ty id work.
+ let len = bytes.len() + 1;
+ let ty = quote_ty!(ctx.ext_cx(), [u8; $len]);
+
+ match String::from_utf8(bytes.clone()) {
+ Ok(string) => {
+ const_item.build(helpers::ast_ty::cstr_expr(string))
+ .build(quote_ty!(ctx.ext_cx(), &'static $ty))
+ }
+ Err(..) => {
+ const_item
+ .build(helpers::ast_ty::byte_array_expr(bytes))
+ .build(ty)
+ }
+ }
+ }
+ VarType::Float(f) => {
+ const_item.build(helpers::ast_ty::float_expr(f))
+ .build(ty)
+ }
+ VarType::Char(c) => {
+ const_item
+ .build(aster::AstBuilder::new().expr().lit().byte(c))
+ .build(ty)
+ }
+ };
+
+ result.push(item);
} else {
let mut attrs = vec![];
if let Some(mangled) = self.mangled_name() {
diff --git a/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs
index 85721978..bda3e3c8 100644
--- a/libbindgen/src/ir/context.rs
+++ b/libbindgen/src/ir/context.rs
@@ -222,7 +222,7 @@ impl<'ctx> BindgenContext<'ctx> {
error!("Valid declaration with no USR: {:?}, {:?}",
declaration,
location);
- return;
+ TypeKey::Declaration(declaration)
};
let old = self.types.insert(key, id);
@@ -609,8 +609,7 @@ impl<'ctx> BindgenContext<'ctx> {
-> Option<ItemId> {
use clangll::{CXCursor_ClassTemplate,
CXCursor_ClassTemplatePartialSpecialization,
- CXCursor_TypeAliasTemplateDecl,
- CXCursor_TypeRef};
+ CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
ty,
location,
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs
index 1f05f92f..253db8c0 100644
--- a/libbindgen/src/ir/item.rs
+++ b/libbindgen/src/ir/item.rs
@@ -840,11 +840,7 @@ impl ClangItemParser for Item {
ctx: &mut BindgenContext)
-> ItemId {
let id = ctx.next_item_id();
- Self::from_ty_or_ref_with_id(id,
- ty,
- location,
- parent_id,
- ctx)
+ Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx)
}
/// Parse a C++ type. If we find a reference to a type that has not been
diff --git a/libbindgen/src/ir/ty.rs b/libbindgen/src/ir/ty.rs
index 34af2db5..1cd255a5 100644
--- a/libbindgen/src/ir/ty.rs
+++ b/libbindgen/src/ir/ty.rs
@@ -123,6 +123,14 @@ impl Type {
Self::new(Some(name), None, kind, false)
}
+ /// Is this a floating point type?
+ pub fn is_float(&self) -> bool {
+ match self.kind {
+ TypeKind::Float(..) => true,
+ _ => false,
+ }
+ }
+
/// Is this an integer type?
pub fn is_integer(&self) -> bool {
match self.kind {
@@ -667,7 +675,7 @@ impl Type {
TypeKind::TemplateAlias(inner.unwrap(), args)
}
CXCursor_TemplateRef => {
- let referenced = location.referenced().expect("expected value, got none");
+ let referenced = location.referenced().unwrap();
let referenced_ty = referenced.cur_type();
let referenced_declaration =
Some(referenced_ty.declaration());
@@ -679,7 +687,7 @@ impl Type {
ctx);
}
CXCursor_TypeRef => {
- let referenced = location.referenced().expect("expected value, got none");
+ let referenced = location.referenced().unwrap();
let referenced_ty = referenced.cur_type();
let referenced_declaration =
Some(referenced_ty.declaration());
diff --git a/libbindgen/src/ir/var.rs b/libbindgen/src/ir/var.rs
index d0c4d9ca..3270b332 100644
--- a/libbindgen/src/ir/var.rs
+++ b/libbindgen/src/ir/var.rs
@@ -8,7 +8,20 @@ use super::context::{BindgenContext, ItemId};
use super::function::cursor_mangling;
use super::int::IntKind;
use super::item::Item;
-use super::ty::TypeKind;
+use super::ty::{FloatKind, TypeKind};
+
+/// The type for a constant variable.
+#[derive(Debug)]
+pub enum VarType {
+ /// An integer.
+ Int(i64),
+ /// A floating point number.
+ Float(f64),
+ /// A character.
+ Char(u8),
+ /// A string, not necessarily well-formed utf-8.
+ String(Vec<u8>),
+}
/// A `Var` is our intermediate representation of a variable.
#[derive(Debug)]
@@ -19,9 +32,8 @@ pub struct Var {
mangled_name: Option<String>,
/// The type of the variable.
ty: ItemId,
- /// TODO: support non-integer constants?
- /// The integer value of the variable.
- val: Option<i64>,
+ /// The value of the variable, that needs to be suitable for `ty`.
+ val: Option<VarType>,
/// Whether this variable is const.
is_const: bool,
}
@@ -31,7 +43,7 @@ impl Var {
pub fn new(name: String,
mangled: Option<String>,
ty: ItemId,
- val: Option<i64>,
+ val: Option<VarType>,
is_const: bool)
-> Var {
assert!(!name.is_empty());
@@ -50,8 +62,8 @@ impl Var {
}
/// The value of this constant variable, if any.
- pub fn val(&self) -> Option<i64> {
- self.val
+ pub fn val(&self) -> Option<&VarType> {
+ self.val.as_ref()
}
/// Get this variable's type.
@@ -76,6 +88,7 @@ impl ClangSubItemParser for Var {
-> Result<ParseResult<Self>, ParseError> {
use clangll::*;
use cexpr::expr::EvalResult;
+ use cexpr::literal::CChar;
match cursor.kind() {
CXCursor_MacroDefinition => {
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
@@ -105,13 +118,32 @@ impl ClangSubItemParser for Var {
// enforce utf8 there, so we should have already panicked at
// this point.
let name = String::from_utf8(id).unwrap();
- let (int_kind, val) = match value {
- // TODO(emilio): Handle the non-invalid ones!
- EvalResult::Float(..) |
- EvalResult::Char(..) |
- EvalResult::Str(..) |
+ let (type_kind, val) = match value {
EvalResult::Invalid => return Err(ParseError::Continue),
-
+ EvalResult::Float(f) => {
+ (TypeKind::Float(FloatKind::Float), VarType::Float(f))
+ }
+ EvalResult::Char(c) => {
+ let c = match c {
+ CChar::Char(c) => {
+ assert_eq!(c.len_utf8(), 1);
+ c as u8
+ }
+ CChar::Raw(c) => {
+ assert!(c <= ::std::u8::MAX as u64);
+ c as u8
+ }
+ };
+
+ (TypeKind::Int(IntKind::U8), VarType::Char(c))
+ }
+ EvalResult::Str(val) => {
+ let char_ty =
+ Item::builtin_type(TypeKind::Int(IntKind::U8),
+ true,
+ ctx);
+ (TypeKind::Pointer(char_ty), VarType::String(val))
+ }
EvalResult::Int(Wrapping(value)) => {
let kind = ctx.options()
.type_chooser
@@ -131,11 +163,11 @@ impl ClangSubItemParser for Var {
}
});
- (kind, value)
+ (TypeKind::Int(kind), VarType::Int(value))
}
};
- let ty = Item::builtin_type(TypeKind::Int(int_kind), true, ctx);
+ let ty = Item::builtin_type(type_kind, true, ctx);
Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true),
Some(cursor)))
@@ -159,19 +191,37 @@ impl ClangSubItemParser for Var {
// tests/headers/inner_const.hpp
//
// That's fine because in that case we know it's not a literal.
- let value = ctx.safe_resolve_type(ty)
- .and_then(|t| t.safe_canonical_type(ctx))
- .and_then(|t| if t.is_integer() { Some(t) } else { None })
- .and_then(|_| {
- get_integer_literal_from_cursor(&cursor,
- ctx.translation_unit())
- });
+ let canonical_ty = ctx.safe_resolve_type(ty)
+ .and_then(|t| t.safe_canonical_type(ctx));
+
+ let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
+ let is_float = canonical_ty.map_or(false, |t| t.is_float());
+
+ // TODO: We could handle `char` more gracefully.
+ // 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 {
+ cursor.evaluate()
+ .as_int()
+ .map(|val| val as i64)
+ .or_else(|| {
+ let tu = ctx.translation_unit();
+ get_integer_literal_from_cursor(&cursor, tu)
+ })
+ .map(VarType::Int)
+ } else if is_float {
+ cursor.evaluate()
+ .as_double()
+ .map(VarType::Float)
+ } else {
+ None
+ };
let mangling = cursor_mangling(&cursor);
-
let var = Var::new(name, mangling, ty, value, is_const);
- Ok(ParseResult::New(var, Some(cursor)))
+ Ok(ParseResult::New(var, Some(cursor)))
}
_ => {
/* TODO */
diff --git a/libbindgen/tests/expectations/tests/constant-evaluate.rs b/libbindgen/tests/expectations/tests/constant-evaluate.rs
new file mode 100644
index 00000000..27b8d829
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/constant-evaluate.rs
@@ -0,0 +1,15 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub const foo: _bindgen_ty_1 = _bindgen_ty_1::foo;
+pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum _bindgen_ty_1 { foo = 4, bar = 8, }
+pub const BAZ: ::std::os::raw::c_longlong = 24;
+pub const fuzz: f64 = 51.;
+pub const BAZZ: ::std::os::raw::c_char = 53;
+pub const WAT: ::std::os::raw::c_char = 0;
diff --git a/libbindgen/tests/expectations/tests/macro_const.rs b/libbindgen/tests/expectations/tests/macro_const.rs
new file mode 100644
index 00000000..9e7eb420
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/macro_const.rs
@@ -0,0 +1,12 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub const foo: &'static [u8; 4usize] = b"bar\x00";
+pub const CHAR: u8 = b'b';
+pub const CHARR: u8 = b'\x00';
+pub const FLOAT: f32 = 5.09;
+pub const FLOAT_EXPR: f32 = 0.005;
+pub const INVALID_UTF8: [u8; 5usize] = [240, 40, 140, 40, 0];
diff --git a/libbindgen/tests/expectations/tests/msvc-no-usr.rs b/libbindgen/tests/expectations/tests/msvc-no-usr.rs
new file mode 100644
index 00000000..8cab8cdc
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/msvc-no-usr.rs
@@ -0,0 +1,19 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct A {
+ pub foo: usize,
+}
+#[test]
+fn bindgen_test_layout_A() {
+ assert_eq!(::std::mem::size_of::<A>() , 8usize);
+ assert_eq!(::std::mem::align_of::<A>() , 8usize);
+}
+impl Clone for A {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/libbindgen/tests/expectations/tests/type_alias_partial_template_especialization.rs
index 70b5f66c..70b5f66c 100644
--- a/tests/expectations/tests/type_alias_partial_template_especialization.rs
+++ b/libbindgen/tests/expectations/tests/type_alias_partial_template_especialization.rs
diff --git a/tests/expectations/tests/type_alias_template_specialized.rs b/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs
index 989f2015..989f2015 100644
--- a/tests/expectations/tests/type_alias_template_specialized.rs
+++ b/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs
diff --git a/libbindgen/tests/headers/constant-evaluate.h b/libbindgen/tests/headers/constant-evaluate.h
new file mode 100644
index 00000000..2790d603
--- /dev/null
+++ b/libbindgen/tests/headers/constant-evaluate.h
@@ -0,0 +1,11 @@
+// bindgen-unstable
+
+enum {
+ foo = 4,
+ bar = 8,
+};
+
+const long long BAZ = (1 << foo) | bar;
+const double fuzz = (1 + 50.0f);
+const char BAZZ = '5';
+const char WAT = '\0';
diff --git a/libbindgen/tests/headers/macro_const.h b/libbindgen/tests/headers/macro_const.h
new file mode 100644
index 00000000..c28a3f6b
--- /dev/null
+++ b/libbindgen/tests/headers/macro_const.h
@@ -0,0 +1,7 @@
+#define foo "bar"
+#define CHAR 'b'
+#define CHARR '\0'
+#define FLOAT 5.09f
+#define FLOAT_EXPR (5 / 1000.0f)
+
+#define INVALID_UTF8 "\xf0\x28\x8c\x28"
diff --git a/libbindgen/tests/headers/msvc-no-usr.hpp b/libbindgen/tests/headers/msvc-no-usr.hpp
new file mode 100644
index 00000000..b15e49f5
--- /dev/null
+++ b/libbindgen/tests/headers/msvc-no-usr.hpp
@@ -0,0 +1,8 @@
+
+typedef unsigned long long size_t;
+
+class A {
+ const size_t foo;
+
+ A() : foo(5) {}
+};
diff --git a/tests/headers/type_alias_partial_template_especialization.hpp b/libbindgen/tests/headers/type_alias_partial_template_especialization.hpp
index dfc36786..dfc36786 100644
--- a/tests/headers/type_alias_partial_template_especialization.hpp
+++ b/libbindgen/tests/headers/type_alias_partial_template_especialization.hpp
diff --git a/tests/headers/type_alias_template_specialized.hpp b/libbindgen/tests/headers/type_alias_template_specialized.hpp
index a2d32b56..a2d32b56 100644
--- a/tests/headers/type_alias_template_specialized.hpp
+++ b/libbindgen/tests/headers/type_alias_template_specialized.hpp
diff --git a/libbindgen/tests/tests.rs b/libbindgen/tests/tests.rs
index 63503282..e4a62523 100644
--- a/libbindgen/tests/tests.rs
+++ b/libbindgen/tests/tests.rs
@@ -4,7 +4,7 @@ extern crate libbindgen;
extern crate shlex;
use std::fs;
-use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
+use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
#[path="../../src/options.rs"]
@@ -32,11 +32,18 @@ fn compare_generated_header(header: &PathBuf,
};
let mut buffer = String::new();
- let f = try!(fs::File::open(&expected));
- let _ = try!(BufReader::new(f).read_to_string(&mut buffer));
+ {
+ if let Ok(expected_file) = fs::File::open(&expected) {
+ try!(BufReader::new(expected_file).read_to_string(&mut buffer));
+ }
+ }
if output == buffer {
- return Ok(());
+ if !output.is_empty() {
+ return Ok(());
+ }
+ return Err(Error::new(ErrorKind::Other,
+ "Something's gone really wrong!"))
}
println!("diff expected generated");
@@ -50,21 +57,34 @@ fn compare_generated_header(header: &PathBuf,
diff::Result::Right(r) => println!("+{}", r),
}
}
+
+ // Override the diff.
+ {
+ let mut expected_file = try!(fs::File::create(&expected));
+ try!(expected_file.write_all(output.as_bytes()));
+ }
+
Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}
fn create_bindgen_builder(header: &PathBuf)
- -> Result<libbindgen::Builder, Error> {
+ -> Result<Option<libbindgen::Builder>, Error> {
let source = try!(fs::File::open(header));
let reader = BufReader::new(source);
// Scoop up bindgen-flags from test header
- let line: String = try!(reader.lines().take(1).collect());
- let flags: Vec<String> = if line.contains("bindgen-flags:") {
- line.split("bindgen-flags:").last().and_then(shlex::split)
- } else {
- None
- }.unwrap_or(Vec::with_capacity(2));
+ let mut flags = Vec::with_capacity(2);
+
+ for line in reader.lines().take(2) {
+ let line = try!(line);
+ if line.contains("bindgen-flags: ") {
+ let extra_flags = line.split("bindgen-flags: ")
+ .last().and_then(shlex::split).unwrap();
+ flags.extend(extra_flags.into_iter());
+ } else if line.contains("bindgen-unstable") && cfg!(feature = "llvm_stable") {
+ return Ok(None)
+ }
+ }
// Fool builder_from_flags() into believing it has real env::args_os...
// - add "bindgen" as executable name 0th element
@@ -86,7 +106,8 @@ fn create_bindgen_builder(header: &PathBuf)
.map(ToString::to_string)
.chain(flags.into_iter());
- builder_from_flags(args).map(|(builder, _)| builder.no_unstable_rust())
+ builder_from_flags(args)
+ .map(|(builder, _)| Some(builder.no_unstable_rust()))
}
macro_rules! test_header {
@@ -94,9 +115,18 @@ macro_rules! test_header {
#[test]
fn $function() {
let header = PathBuf::from($header);
- let _ = create_bindgen_builder(&header)
- .and_then(|builder| compare_generated_header(&header, builder))
- .map_err(|err| panic!(format!("{}", err)) );
+ let result = create_bindgen_builder(&header)
+ .and_then(|builder| {
+ if let Some(builder) = builder {
+ compare_generated_header(&header, builder)
+ } else {
+ Ok(())
+ }
+ });
+
+ if let Err(err) = result {
+ panic!("{}", err);
+ }
}
)
}