diff options
author | Jean-Philippe DUFRAIGNE <j.dufraigne@gmail.com> | 2016-11-08 20:19:13 +0000 |
---|---|---|
committer | Jean-Philippe DUFRAIGNE <j.dufraigne@gmail.com> | 2016-11-11 21:17:08 +0000 |
commit | b5d879ae4a88068e96b9fc701e55cd64e2a9ba39 (patch) | |
tree | 1cdb16fcf0ebdc0c43a841521cdb565df9553c89 | |
parent | 08f56c3fc4b204313918f9dbbce935ace4365f43 (diff) |
Use __BindegenComplex for C Complex Fix #72
C complex only exists for floating point types.
C Complex are built in types
long double _Complex is not supported.
Long double would be an f128, runing generated binding test produces:
assertion failed: `(left == right)` (left: `16`, right: `32`)',
tests/expectations/tests/complex.rs:72
We test global long double _Complex because it does not require
layout tests.
Handle all the different way a complex can be present in
BindgenContext calling generated_bindegen_complex to indicate
that __BindgenContext will need to be added.
-rw-r--r-- | src/codegen/helpers.rs | 47 | ||||
-rwxr-xr-x | src/codegen/mod.rs | 57 | ||||
-rw-r--r-- | src/ir/context.rs | 26 | ||||
-rw-r--r-- | src/ir/ty.rs | 16 | ||||
-rw-r--r-- | tests/expectations/tests/complex.rs | 76 | ||||
-rw-r--r-- | tests/expectations/tests/complex_global.rs | 24 | ||||
-rw-r--r-- | tests/expectations/tests/convert-floats.rs | 10 | ||||
-rw-r--r-- | tests/headers/complex.h | 23 | ||||
-rw-r--r-- | tests/headers/complex_global.h | 3 | ||||
-rw-r--r-- | tests/headers/convert-floats.h | 2 | ||||
-rw-r--r-- | tests/headers/whitelist_basic.hpp | 1 |
11 files changed, 186 insertions, 99 deletions
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index 234dcbcc..016ba478 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -71,3 +71,50 @@ impl BlobTyBuilder { } } } + +pub mod ast_ty { + use aster; + use ir::context::BindgenContext; + use ir::ty::FloatKind; + use syntax::ast; + use syntax::ptr::P; + + pub fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { + let ident = ctx.rust_ident_raw(&name); + match ctx.options().ctypes_prefix { + Some(ref prefix) => { + let prefix = ctx.rust_ident_raw(prefix); + quote_ty!(ctx.ext_cx(), $prefix::$ident) + } + None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident), + } + } + + pub fn float_kind_rust_type(ctx: &BindgenContext, + fk: FloatKind) + -> P<ast::Ty> { + macro_rules! raw { + ($ty: ident) => { + raw_type(ctx, stringify!($ty)) + } + } + // TODO: we probably should just take the type layout into + // account? + // + // Also, maybe this one shouldn't be the default? + // + // FIXME: `c_longdouble` doesn't seem to be defined in some + // systems, so we use `c_double` directly. + match (fk, ctx.options().convert_floats) { + (FloatKind::Float, true) => aster::ty::TyBuilder::new().f32(), + (FloatKind::Double, true) | + (FloatKind::LongDouble, true) => aster::ty::TyBuilder::new().f64(), + (FloatKind::Float, false) => raw!(c_float), + (FloatKind::Double, false) | + (FloatKind::LongDouble, false) => raw!(c_double), + (FloatKind::Float128, _) => { + aster::ty::TyBuilder::new().array(16).u8() + } + } + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 3bee69b6..1511f629 100755 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -336,6 +336,7 @@ impl CodeGenerator for Type { TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Float(..) | + TypeKind::Complex(..) | TypeKind::Array(..) | TypeKind::Pointer(..) | TypeKind::BlockPointer | @@ -1549,21 +1550,12 @@ impl ItemToRustTy for Item { } } -fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { - let ident = ctx.rust_ident_raw(&name); - match ctx.options().ctypes_prefix { - Some(ref prefix) => { - let prefix = ctx.rust_ident_raw(prefix); - quote_ty!(ctx.ext_cx(), $prefix::$ident) - } - None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident), - } -} - impl ToRustTy for Type { type Extra = Item; fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> { + use self::helpers::ast_ty::*; + macro_rules! raw { ($ty: ident) => { raw_type(ctx, stringify!($ty)) @@ -1608,24 +1600,12 @@ impl ToRustTy for Type { } } } - TypeKind::Float(fk) => { - // TODO: we probably should just take the type layout into - // account? - // - // Also, maybe this one shouldn't be the default? - // - // FIXME: `c_longdouble` doesn't seem to be defined in some - // systems, so we use `c_double` directly. - use ir::ty::FloatKind; - match (fk, ctx.options().convert_floats) { - (FloatKind::Float, true) => aster::ty::TyBuilder::new().f32(), - (FloatKind::Double, true) | - (FloatKind::LongDouble, true) => aster::ty::TyBuilder::new().f64(), - (FloatKind::Float, false) => raw!(c_float), - (FloatKind::Double, false) | - (FloatKind::LongDouble, false) => raw!(c_double), - (FloatKind::Float128, _) => aster::ty::TyBuilder::new().array(16).u8(), - } + TypeKind::Float(fk) => float_kind_rust_type(ctx, fk), + TypeKind::Complex(fk) => { + let float_path = float_kind_rust_type(ctx, fk); + + ctx.generated_bindegen_complex(); + quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) } TypeKind::Function(ref fs) => { let ty = fs.to_rust_ty(ctx, item); @@ -1900,6 +1880,9 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { if saw_union && !context.options().unstable_rust { utils::prepend_union_types(context, &mut result); } + if context.need_bindegen_complex_type() { + utils::prepend_complex_type(context, &mut result); + } result }) } @@ -1981,6 +1964,22 @@ mod utils { result.extend(old_items.into_iter()); } + pub fn prepend_complex_type(ctx: &BindgenContext, + result: &mut Vec<P<ast::Item>>) { + let complex_type = quote_item!(ctx.ext_cx(), + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C)] + pub struct __BindgenComplex<T> { + pub re: T, + pub im: T + } + ) + .unwrap(); + + let items = vec![complex_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } pub fn build_templated_path(item: &Item, ctx: &BindgenContext, diff --git a/src/ir/context.rs b/src/ir/context.rs index 92c6fb49..c7949bef 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -5,6 +5,7 @@ use cexpr; use clang::{self, Cursor}; use parse::ClangItemParser; use std::borrow::Cow; +use std::cell::Cell; use std::collections::{HashMap, hash_map}; use std::collections::btree_map::{self, BTreeMap}; use std::fmt; @@ -99,6 +100,9 @@ pub struct BindgenContext<'ctx> { /// The options given by the user via cli or other medium. options: BindgenOptions, + + /// Whether a bindgen complex was generated + generated_bindegen_complex: Cell<bool>, } impl<'ctx> BindgenContext<'ctx> { @@ -134,6 +138,7 @@ impl<'ctx> BindgenContext<'ctx> { index: index, translation_unit: translation_unit, options: options, + generated_bindegen_complex: Cell::new(false), }; me.add_item(root_module, None, None); @@ -698,6 +703,17 @@ impl<'ctx> BindgenContext<'ctx> { CXType_Double => TypeKind::Float(FloatKind::Double), CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), CXType_Float128 => TypeKind::Float(FloatKind::Float128), + CXType_Complex => { + let float_type = ty.elem_type() + .expect("Not able to resolve complex type?"); + let float_kind = match float_type.kind() { + CXType_Float => FloatKind::Float, + CXType_Double => FloatKind::Double, + CXType_LongDouble => FloatKind::LongDouble, + _ => panic!("Non floating-type complex?"), + }; + TypeKind::Complex(float_kind) + } _ => return None, }; @@ -930,6 +946,16 @@ impl<'ctx> BindgenContext<'ctx> { self.rust_ident_raw("std") } } + + /// Call if a binden complex is generated + pub fn generated_bindegen_complex(&self) { + self.generated_bindegen_complex.set(true) + } + + /// Whether we need to generate the binden complex type + pub fn need_bindegen_complex_type(&self) -> bool { + self.generated_bindegen_complex.get() + } } /// An iterator over whitelisted items. diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 4c2ef5d8..d5ac6116 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -334,6 +334,7 @@ impl Type { TypeKind::Comp(..) | TypeKind::Int(..) | TypeKind::Float(..) | + TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | @@ -386,6 +387,9 @@ pub enum TypeKind { /// A floating point type. Float(FloatKind), + /// A complex floating point type. + Complex(FloatKind), + /// A type alias, with a name, that points to another type. Alias(String, ItemId), @@ -463,6 +467,7 @@ impl Type { TypeKind::Named(..) | TypeKind::Int(..) | TypeKind::Float(..) | + TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | @@ -801,17 +806,6 @@ impl Type { .expect("Not able to resolve array element?"); TypeKind::Array(inner, ty.num_elements().unwrap()) } - // A complex number is always a real and an imaginary part, - // so - // represent that as a two-item array. - CXType_Complex => { - let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), - location, - parent_id, - ctx) - .expect("Not able to resolve array element?"); - TypeKind::Array(inner, 2) - } #[cfg(not(feature="llvm_stable"))] CXType_Elaborated => { return Self::from_clang_ty(potential_id, diff --git a/tests/expectations/tests/complex.rs b/tests/expectations/tests/complex.rs index e11a049e..f2a97952 100644 --- a/tests/expectations/tests/complex.rs +++ b/tests/expectations/tests/complex.rs @@ -4,81 +4,61 @@ #![allow(non_snake_case)] +#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] -#[derive(Debug, Copy)] -pub struct Testdouble { - pub mMember: [f64; 2usize], -} -#[test] -fn bindgen_test_layout_Testdouble() { - assert_eq!(::std::mem::size_of::<Testdouble>() , 16usize); - assert_eq!(::std::mem::align_of::<Testdouble>() , 8usize); -} -impl Clone for Testdouble { - fn clone(&self) -> Self { *self } -} -#[repr(C)] -#[derive(Debug, Copy)] -pub struct TestdoublePtr { - pub mMember: *mut [f64; 2usize], -} -#[test] -fn bindgen_test_layout_TestdoublePtr() { - assert_eq!(::std::mem::size_of::<TestdoublePtr>() , 8usize); - assert_eq!(::std::mem::align_of::<TestdoublePtr>() , 8usize); -} -impl Clone for TestdoublePtr { - fn clone(&self) -> Self { *self } +pub struct __BindgenComplex<T> { + pub re: T, + pub im: T, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Testfloat { - pub mMember: [f32; 2usize], +pub struct TestDouble { + pub mMember: __BindgenComplex<f64>, } #[test] -fn bindgen_test_layout_Testfloat() { - assert_eq!(::std::mem::size_of::<Testfloat>() , 8usize); - assert_eq!(::std::mem::align_of::<Testfloat>() , 4usize); +fn bindgen_test_layout_TestDouble() { + assert_eq!(::std::mem::size_of::<TestDouble>() , 16usize); + assert_eq!(::std::mem::align_of::<TestDouble>() , 8usize); } -impl Clone for Testfloat { +impl Clone for TestDouble { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct TestfloatPtr { - pub mMember: *mut [f32; 2usize], +pub struct TestDoublePtr { + pub mMember: *mut __BindgenComplex<f64>, } #[test] -fn bindgen_test_layout_TestfloatPtr() { - assert_eq!(::std::mem::size_of::<TestfloatPtr>() , 8usize); - assert_eq!(::std::mem::align_of::<TestfloatPtr>() , 8usize); +fn bindgen_test_layout_TestDoublePtr() { + assert_eq!(::std::mem::size_of::<TestDoublePtr>() , 8usize); + assert_eq!(::std::mem::align_of::<TestDoublePtr>() , 8usize); } -impl Clone for TestfloatPtr { +impl Clone for TestDoublePtr { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Testint { - pub mMember: [::std::os::raw::c_int; 2usize], +pub struct TestFloat { + pub mMember: __BindgenComplex<f32>, } #[test] -fn bindgen_test_layout_Testint() { - assert_eq!(::std::mem::size_of::<Testint>() , 8usize); - assert_eq!(::std::mem::align_of::<Testint>() , 4usize); +fn bindgen_test_layout_TestFloat() { + assert_eq!(::std::mem::size_of::<TestFloat>() , 8usize); + assert_eq!(::std::mem::align_of::<TestFloat>() , 4usize); } -impl Clone for Testint { +impl Clone for TestFloat { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct TestintPtr { - pub mMember: *mut [::std::os::raw::c_int; 2usize], +pub struct TestFloatPtr { + pub mMember: *mut __BindgenComplex<f32>, } #[test] -fn bindgen_test_layout_TestintPtr() { - assert_eq!(::std::mem::size_of::<TestintPtr>() , 8usize); - assert_eq!(::std::mem::align_of::<TestintPtr>() , 8usize); +fn bindgen_test_layout_TestFloatPtr() { + assert_eq!(::std::mem::size_of::<TestFloatPtr>() , 8usize); + assert_eq!(::std::mem::align_of::<TestFloatPtr>() , 8usize); } -impl Clone for TestintPtr { +impl Clone for TestFloatPtr { fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/tests/complex_global.rs b/tests/expectations/tests/complex_global.rs new file mode 100644 index 00000000..badc4d1f --- /dev/null +++ b/tests/expectations/tests/complex_global.rs @@ -0,0 +1,24 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] +#[repr(C)] +pub struct __BindgenComplex<T> { + pub re: T, + pub im: T, +} +extern "C" { + #[link_name = "globalValueFloat"] + pub static mut globalValueFloat: __BindgenComplex<f32>; +} +extern "C" { + #[link_name = "globalValueDouble"] + pub static mut globalValueDouble: __BindgenComplex<f64>; +} +extern "C" { + #[link_name = "globalValueLongDouble"] + pub static mut globalValueLongDouble: __BindgenComplex<f64>; +} diff --git a/tests/expectations/tests/convert-floats.rs b/tests/expectations/tests/convert-floats.rs index ed5bcdcd..5cd38c13 100644 --- a/tests/expectations/tests/convert-floats.rs +++ b/tests/expectations/tests/convert-floats.rs @@ -4,6 +4,12 @@ #![allow(non_snake_case)] +#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] +#[repr(C)] +pub struct __BindgenComplex<T> { + pub re: T, + pub im: T, +} #[repr(C)] #[derive(Debug, Copy)] pub struct foo { @@ -11,10 +17,12 @@ pub struct foo { pub baz: ::std::os::raw::c_float, pub bazz: ::std::os::raw::c_double, pub bazzz: *mut ::std::os::raw::c_double, + pub complexFloat: __BindgenComplex<::std::os::raw::c_float>, + pub complexDouble: __BindgenComplex<::std::os::raw::c_double>, } #[test] fn bindgen_test_layout_foo() { - assert_eq!(::std::mem::size_of::<foo>() , 24usize); + assert_eq!(::std::mem::size_of::<foo>() , 48usize); assert_eq!(::std::mem::align_of::<foo>() , 8usize); } impl Clone for foo { diff --git a/tests/headers/complex.h b/tests/headers/complex.h index ad7af59f..04877a4e 100644 --- a/tests/headers/complex.h +++ b/tests/headers/complex.h @@ -1,13 +1,16 @@ -#define COMPLEX_TEST(ty_) \ - struct Test##ty_ { \ - ty_ _Complex mMember; \ - \ - }; \ - struct Test##ty_##Ptr { \ - ty_ _Complex* mMember; \ +#define COMPLEX_TEST(ty_, name_) \ + struct Test##name_ { \ + ty_ _Complex mMember; \ + \ + }; \ + struct Test##name_##Ptr { \ + ty_ _Complex* mMember; \ }; -COMPLEX_TEST(double) -COMPLEX_TEST(float) -COMPLEX_TEST(int) +COMPLEX_TEST(double, Double) +COMPLEX_TEST(float, Float) + +// FIXME: 128-byte-aligned in some machines +// which we can't support right now in Rust. +// COMPLEX_TEST(long double, LongDouble) diff --git a/tests/headers/complex_global.h b/tests/headers/complex_global.h new file mode 100644 index 00000000..d9f9fb01 --- /dev/null +++ b/tests/headers/complex_global.h @@ -0,0 +1,3 @@ +float _Complex globalValueFloat; +double _Complex globalValueDouble; +long double _Complex globalValueLongDouble; diff --git a/tests/headers/convert-floats.h b/tests/headers/convert-floats.h index 0e0ebd33..08d9fe0b 100644 --- a/tests/headers/convert-floats.h +++ b/tests/headers/convert-floats.h @@ -4,4 +4,6 @@ struct foo { float bar, baz; double bazz; long double* bazzz; + float _Complex complexFloat; + double _Complex complexDouble; }; diff --git a/tests/headers/whitelist_basic.hpp b/tests/headers/whitelist_basic.hpp index 661528ba..8424f75a 100644 --- a/tests/headers/whitelist_basic.hpp +++ b/tests/headers/whitelist_basic.hpp @@ -12,4 +12,5 @@ class WhitelistMe { struct DontWhitelistMe { void* foo; + double _Complex noComplexGenerated; }; |