Skip to content

Commit 3d418de

Browse files
committed
Merge pull request rust-lang#263 from nox/enum-fixes
Some enum and build fixes
2 parents 4afdf51 + 621a81a commit 3d418de

File tree

7 files changed

+117
-21
lines changed

7 files changed

+117
-21
lines changed

build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ fn main() {
148148
println!("cargo:rustc-link-lib=dylib=clang");
149149
}
150150
}
151+
println!("cargo:rerun-if-changed=");
151152
} else {
152153
panic!("Unable to find {}", clang_lib);
153154
}

src/gen.rs

+74-20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std;
12
use std::cell::RefCell;
23
use std::vec::Vec;
34
use std::rc::Rc;
@@ -213,7 +214,7 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
213214
e.name = unnamed_name(&mut ctx, e.name.clone());
214215
}
215216
let e = ei.borrow();
216-
defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, &e.items).into_iter())
217+
defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, e.layout, &e.items).into_iter())
217218
},
218219
GVar(vi) => {
219220
let v = vi.borrow();
@@ -477,7 +478,7 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, ty: &Type) -> Vec<P<ast::Item>
477478
if is_empty {
478479
ei.borrow_mut().name = name.clone();
479480
let e = ei.borrow();
480-
cenum_to_rs(ctx, name, e.kind, &e.items)
481+
cenum_to_rs(ctx, name, e.kind, e.layout, &e.items)
481482
} else {
482483
vec!(mk_item(ctx, name, ty))
483484
}
@@ -699,24 +700,81 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
699700
})
700701
}
701702

702-
fn enum_kind_to_rust_type_name(kind: IKind) -> &'static str {
703+
fn enum_kind_is_signed(kind: IKind) -> bool {
703704
match kind {
704-
ISChar => "i8",
705-
IUChar => "u8",
706-
IShort => "i16",
707-
IUShort => "u16",
708-
IInt => "i32",
709-
IUInt => "u32",
710-
ILong => "i64",
711-
IULong => "u64",
712-
_ => unreachable!(),
705+
IBool => false,
706+
ISChar => true,
707+
IUChar => false,
708+
IShort => true,
709+
IUShort => false,
710+
IInt => true,
711+
IUInt => false,
712+
ILong => true,
713+
IULong => false,
714+
ILongLong => true,
715+
IULongLong => false,
713716
}
714717
}
715718

716-
fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, enum_items: &[EnumItem])
719+
fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str {
720+
match (signed, size) {
721+
(true, 1) => "i8",
722+
(false, 1) => "u8",
723+
(true, 2) => "i16",
724+
(false, 2) => "u16",
725+
(true, 4) => "i32",
726+
(false, 4) => "u32",
727+
(true, 8) => "i64",
728+
(false, 8) => "u64",
729+
_ => unreachable!("invalid enum decl: signed: {}, size: {}", signed, size),
730+
}
731+
}
732+
733+
fn enum_size_to_unsigned_max_value(size: usize) -> u64 {
734+
match size {
735+
1 => std::u8::MAX as u64,
736+
2 => std::u16::MAX as u64,
737+
4 => std::u32::MAX as u64,
738+
8 => std::u64::MAX,
739+
_ => unreachable!("invalid enum size: {}", size)
740+
}
741+
}
742+
743+
fn cenum_value_to_int_lit(
744+
ctx: &mut GenCtx,
745+
enum_is_signed: bool,
746+
size: usize,
747+
value: i64)
748+
-> P<ast::Expr> {
749+
if enum_is_signed {
750+
let int_lit =
751+
ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
752+
let expr = ctx.ext_cx.expr_lit(ctx.span, int_lit);
753+
if value < 0 {
754+
ctx.ext_cx.expr(
755+
ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr))
756+
} else {
757+
expr
758+
}
759+
} else {
760+
let u64_value =
761+
value as u64 & enum_size_to_unsigned_max_value(size);
762+
let int_lit =
763+
ast::LitKind::Int(u64_value, ast::LitIntType::Unsuffixed);
764+
ctx.ext_cx.expr_lit(ctx.span, int_lit)
765+
}
766+
}
767+
768+
769+
fn cenum_to_rs(ctx: &mut GenCtx,
770+
name: String,
771+
kind: IKind,
772+
layout: Layout,
773+
enum_items: &[EnumItem])
717774
-> Vec<P<ast::Item>> {
718775
let enum_name = ctx.ext_cx.ident_of(&name);
719776
let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name);
777+
let enum_is_signed = enum_kind_is_signed(kind);
720778

721779
let mut variants = vec![];
722780
let mut found_values = HashMap::new();
@@ -741,12 +799,8 @@ fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, enum_items: &[EnumIt
741799

742800
found_values.insert(item.val, name);
743801

744-
let int_lit = ast::LitKind::Int(item.val.abs() as u64, ast::LitIntType::Unsuffixed);
745-
let mut value = ctx.ext_cx.expr_lit(ctx.span, int_lit);
746-
if item.val < 0 {
747-
let negated = ast::ExprKind::Unary(ast::UnOp::Neg, value);
748-
value = ctx.ext_cx.expr(ctx.span, negated);
749-
}
802+
let value = cenum_value_to_int_lit(
803+
ctx, enum_is_signed, layout.size, item.val);
750804

751805
variants.push(respan(ctx.span, ast::Variant_ {
752806
name: name,
@@ -756,7 +810,7 @@ fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, enum_items: &[EnumIt
756810
}));
757811
}
758812

759-
let enum_repr = InternedString::new(enum_kind_to_rust_type_name(kind));
813+
let enum_repr = InternedString::new(enum_size_to_rust_type_name(enum_is_signed, layout.size));
760814

761815
let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr);
762816
let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]);

src/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl Type {
142142
}
143143
}
144144

145-
#[derive(Copy, Clone, PartialEq)]
145+
#[derive(Copy, Clone, Debug, PartialEq)]
146146
pub struct Layout {
147147
pub size: usize,
148148
pub align: usize,

tests/headers/enum_explicit_type.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ enum Bigger: unsigned short {
1212
Much = 255,
1313
Larger
1414
};
15+
16+
enum MuchLong: long {
17+
MuchLow = -4294967296,
18+
};
19+
20+
enum MuchLongLong: unsigned long long {
21+
MuchHigh = 4294967296,
22+
};

tests/headers/overflowed_enum.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
enum Foo {
2+
BAP_ARM = 0x93fcb9,
3+
BAP_X86 = 0xb67eed,
4+
BAP_X86_64 = 0xba7b274f,
5+
};
6+
7+
enum Bar: unsigned short {
8+
One = 1,
9+
Big = 65538,
10+
};

tests/support.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub fn generate_bindings(filename: &str) -> Result<Vec<P<ast::Item>>, ()> {
2727
let mut options:BindgenOptions = Default::default();
2828
if filename.ends_with("hpp") {
2929
options.clang_args.push("-std=c++11".to_string());
30+
options.clang_args.push("-Wno-narrowing".to_string());
3031
}
3132
options.clang_args.push(filename.to_string());
3233

tests/test_enum.rs

+22
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,27 @@ fn with_explicitly_typed_cxx_enum() {
4949
#[derive(Clone, Copy)]
5050
#[repr(u16)]
5151
pub enum Enum_Bigger { Much = 255, Larger = 256, }
52+
#[derive(Clone, Copy)]
53+
#[repr(i64)]
54+
pub enum Enum_MuchLong { MuchLow = -4294967296, }
55+
#[derive(Clone, Copy)]
56+
#[repr(u64)]
57+
pub enum Enum_MuchLongLong { MuchHigh = 4294967296, }
58+
");
59+
}
60+
61+
#[test]
62+
fn with_overflowed_enum_value() {
63+
assert_bind_eq("headers/overflowed_enum.hpp", "
64+
#[derive(Clone, Copy)]
65+
#[repr(u32)]
66+
pub enum Enum_Foo {
67+
BAP_ARM = 9698489,
68+
BAP_X86 = 11960045,
69+
BAP_X86_64 = 3128633167,
70+
}
71+
#[derive(Clone, Copy)]
72+
#[repr(u16)]
73+
pub enum Enum_Bar { One = 1, Big = 2, }
5274
");
5375
}

0 commit comments

Comments
 (0)