Skip to content

Use __BindegenComplex for C Complex #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
}
}
57 changes: 28 additions & 29 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ impl CodeGenerator for Type {
TypeKind::NullPtr |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Array(..) |
TypeKind::Pointer(..) |
TypeKind::BlockPointer |
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to call saw_complex just here, and remove the rest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nevermind, you don't have access to the result. Maybe worth moving that to the context inside a Cell<bool>, and checking that instead? Even better would be something like Cell<SeenFlags>, where SeenFlags is a bitflags!, but for now moving saw_union and saw_complex to BindgenContext is fine, the other can be a followup if you want.

Otherwise you'll need to check for virtually every possible type, function arguments, etc...

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);
Expand Down Expand Up @@ -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
})
}
Expand Down Expand Up @@ -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,
Expand Down
26 changes: 26 additions & 0 deletions src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably:

let float_kind = match float_type.kind() {
    CXType_Float => FloatKind::Float,
    CXType_Double => FloatKind::Double,
    CXType_LongDouble => FloatKind::LongDouble,
    _ => panic!("Non floating-type complex?"),
};

Or, you could also add a FloatKind::from_ty(Type) -> Option<FloatKind> function, though that might be overkill for this, so leaving a match is totally fine :)

CXType_Float => FloatKind::Float,
CXType_Double => FloatKind::Double,
CXType_LongDouble => FloatKind::LongDouble,
_ => panic!("Non floating-type complex?"),
};
TypeKind::Complex(float_kind)
}
_ => return None,
};

Expand Down Expand Up @@ -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.
Expand Down
16 changes: 5 additions & 11 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ impl Type {
TypeKind::Comp(..) |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Function(..) |
TypeKind::Enum(..) |
TypeKind::Reference(..) |
Expand Down Expand Up @@ -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),

Expand Down Expand Up @@ -463,6 +467,7 @@ impl Type {
TypeKind::Named(..) |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Function(..) |
TypeKind::Enum(..) |
TypeKind::Reference(..) |
Expand Down Expand Up @@ -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,
Expand Down
76 changes: 28 additions & 48 deletions tests/expectations/tests/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
24 changes: 24 additions & 0 deletions tests/expectations/tests/complex_global.rs
Original file line number Diff line number Diff line change
@@ -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>;
}
Loading