Skip to content

Commit 0ef84e9

Browse files
committed
Improve constant generation (float, chars), write docs for it.
1 parent fc4810f commit 0ef84e9

File tree

11 files changed

+114
-30
lines changed

11 files changed

+114
-30
lines changed

libbindgen/src/clang.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,36 +1265,56 @@ pub fn extract_clang_version() -> String {
12651265
unsafe { clang_getClangVersion().into() }
12661266
}
12671267

1268+
/// A wrapper for the result of evaluating an expression.
12681269
#[derive(Debug)]
12691270
pub struct EvalResult {
12701271
x: CXEvalResult,
12711272
}
12721273

12731274
#[cfg(feature = "llvm_stable")]
12741275
impl EvalResult {
1276+
/// Create a dummy EvalResult.
12751277
pub fn new(_: Cursor) -> Self {
12761278
EvalResult {
12771279
x: ::std::ptr::null_mut(),
12781280
}
12791281
}
12801282

1283+
/// Not useful in llvm 3.8.
1284+
pub fn as_double(&self) -> Option<f64> {
1285+
None
1286+
}
1287+
1288+
/// Not useful in llvm 3.8.
12811289
pub fn as_int(&self) -> Option<i32> {
12821290
None
12831291
}
12841292
}
12851293

12861294
#[cfg(not(feature = "llvm_stable"))]
12871295
impl EvalResult {
1296+
/// Evaluate `cursor` and return the result.
12881297
pub fn new(cursor: Cursor) -> Self {
12891298
EvalResult {
12901299
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
12911300
}
12921301
}
12931302

1294-
pub fn kind(&self) -> Enum_CXEvalResultKind {
1303+
fn kind(&self) -> Enum_CXEvalResultKind {
12951304
unsafe { clang_EvalResult_getKind(self.x) }
12961305
}
12971306

1307+
/// Try to get back the result as a double.
1308+
pub fn as_double(&self) -> Option<f64> {
1309+
match self.kind() {
1310+
CXEval_Float => {
1311+
Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
1312+
}
1313+
_ => None,
1314+
}
1315+
}
1316+
1317+
/// Try to get back the result as an integer.
12981318
pub fn as_int(&self) -> Option<i32> {
12991319
match self.kind() {
13001320
CXEval_Int => {

libbindgen/src/codegen/helpers.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,11 @@ pub mod ast_ty {
150150
aster::AstBuilder::new().expr().build_lit(
151151
aster::AstBuilder::new().lit().byte_str(string))
152152
}
153+
154+
pub fn float_expr(f: f64) -> P<ast::Expr> {
155+
use aster::str::ToInternedString;
156+
let interned_str = f.to_string().as_str().to_interned_string();
157+
let kind = ast::LitKind::FloatUnsuffixed(interned_str);
158+
aster::AstBuilder::new().expr().lit().build_lit(kind)
159+
}
153160
}

libbindgen/src/codegen/mod.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,23 +323,36 @@ impl CodeGenerator for Var {
323323
.build(ty)
324324
}
325325
VarType::String(ref bytes) => {
326+
// Account the trailing zero.
327+
//
328+
// TODO: Here we ignore the type we just made up, probably
329+
// we should refactor how the variable type and ty id work.
330+
let len = bytes.len() + 1;
331+
let ty = quote_ty!(ctx.ext_cx(), [u8; $len]);
332+
326333
match String::from_utf8(bytes.clone()) {
327334
Ok(string) => {
328335
const_item
329336
.build(helpers::ast_ty::cstr_expr(string))
330-
.build(ty)
337+
.build(quote_ty!(ctx.ext_cx(), &'static $ty))
331338
}
332339
Err(..) => {
333-
// Account the trailing zero.
334-
let len = bytes.len() + 1;
335-
let ty = quote_ty!(ctx.ext_cx(), [u8; $len]);
336-
337340
const_item
338341
.build(helpers::ast_ty::byte_array_expr(bytes))
339342
.build(ty)
340343
}
341344
}
342345
}
346+
VarType::Float(f) => {
347+
const_item
348+
.build(helpers::ast_ty::float_expr(f))
349+
.build(ty)
350+
}
351+
VarType::Char(c) => {
352+
const_item
353+
.build(aster::AstBuilder::new().expr().lit().byte(c))
354+
.build(ty)
355+
}
343356
};
344357

345358
result.push(item);

libbindgen/src/ir/ty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ impl Type {
123123
Self::new(Some(name), None, kind, false)
124124
}
125125

126+
/// Is this an floating point type?
127+
pub fn is_float(&self) -> bool {
128+
match self.kind {
129+
TypeKind::Float(..) => true,
130+
_ => false,
131+
}
132+
}
133+
126134
/// Is this an integer type?
127135
pub fn is_integer(&self) -> bool {
128136
match self.kind {

libbindgen/src/ir/var.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ use super::context::{BindgenContext, ItemId};
88
use super::function::cursor_mangling;
99
use super::int::IntKind;
1010
use super::item::Item;
11-
use super::ty::TypeKind;
11+
use super::ty::{TypeKind, FloatKind};
1212

1313
#[derive(Debug)]
1414
pub enum VarType {
1515
Int(i64),
16+
Float(f64),
17+
Char(u8),
1618
String(Vec<u8>),
1719
}
1820

@@ -81,6 +83,7 @@ impl ClangSubItemParser for Var {
8183
-> Result<ParseResult<Self>, ParseError> {
8284
use clangll::*;
8385
use cexpr::expr::EvalResult;
86+
use cexpr::literal::CChar;
8487
match cursor.kind() {
8588
CXCursor_MacroDefinition => {
8689
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
@@ -111,11 +114,24 @@ impl ClangSubItemParser for Var {
111114
// this point.
112115
let name = String::from_utf8(id).unwrap();
113116
let (type_kind, val) = match value {
114-
// TODO(emilio): Handle the non-invalid ones!
115-
EvalResult::Float(..) |
116-
EvalResult::Char(..) |
117117
EvalResult::Invalid => return Err(ParseError::Continue),
118-
118+
EvalResult::Float(f) => {
119+
(TypeKind::Float(FloatKind::Float), VarType::Float(f))
120+
}
121+
EvalResult::Char(c) => {
122+
let c = match c {
123+
CChar::Char(c) => {
124+
assert_eq!(c.len_utf8(), 1);
125+
c as u8
126+
}
127+
CChar::Raw(c) => {
128+
assert!(c <= ::std::u8::MAX as u64);
129+
c as u8
130+
}
131+
};
132+
133+
(TypeKind::Int(IntKind::U8), VarType::Char(c))
134+
}
119135
EvalResult::Str(val) => {
120136
let char_ty =
121137
Item::builtin_type(TypeKind::Int(IntKind::U8),
@@ -169,13 +185,16 @@ impl ClangSubItemParser for Var {
169185
// tests/headers/inner_const.hpp
170186
//
171187
// That's fine because in that case we know it's not a literal.
172-
//
173-
// TODO: Strings, stuff like that.
174-
let is_integer = ctx.safe_resolve_type(ty)
175-
.and_then(|t| t.safe_canonical_type(ctx))
176-
.map(|t| t.is_integer())
177-
.unwrap_or(false);
188+
let canonical_ty = ctx.safe_resolve_type(ty)
189+
.and_then(|t| t.safe_canonical_type(ctx));
190+
191+
let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
192+
let is_float = canonical_ty.map_or(false, |t| t.is_float());
178193

194+
// TODO: We could handle `char` more gracefully.
195+
// TODO: Strings, though the lookup is a bit more hard (we need
196+
// to look at the canonical type of the pointee too, and check
197+
// is char, u8, or i8 I guess).
179198
let value = if is_integer {
180199
cursor.evaluate()
181200
.as_int()
@@ -184,14 +203,17 @@ impl ClangSubItemParser for Var {
184203
let tu = ctx.translation_unit();
185204
get_integer_literal_from_cursor(&cursor, tu)
186205
}).map(VarType::Int)
206+
} else if is_float {
207+
cursor.evaluate()
208+
.as_double()
209+
.map(VarType::Float)
187210
} else {
188211
None
189212
};
190213

191-
192214
let mangling = cursor_mangling(&cursor);
193-
194215
let var = Var::new(name, mangling, ty, value, is_const);
216+
195217
Ok(ParseResult::New(var, Some(cursor)))
196218
}
197219
_ => {

tests/expectations/tests/constant-evaluate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
1010
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1111
pub enum _bindgen_ty_1 { foo = 4, bar = 8, }
1212
pub const BAZ: ::std::os::raw::c_longlong = 24;
13+
pub const fuzz: f64 = 51;
14+
pub const BAZZ: ::std::os::raw::c_char = 53;
15+
pub const WAT: ::std::os::raw::c_char = 0;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const foo: &'static [u8; 4usize] = b"bar\x00";
8+
pub const CHAR: u8 = b'b';
9+
pub const CHARR: u8 = b'\x00';
10+
pub const FLOAT: f32 = 5.09;
11+
pub const FLOAT_EXPR: f32 = 0.005;
12+
pub const INVALID_UTF8: [u8; 5usize] = [240, 40, 140, 40, 0];

tests/expectations/tests/macro_str.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/headers/constant-evaluate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ enum {
55
};
66

77
const long long BAZ = (1 << foo) | bar;
8+
const double fuzz = (1 + 50.0f);
9+
const char BAZZ = '5';
10+
const char WAT = '\0';

tests/headers/macro_const.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#define foo "bar"
2+
#define CHAR 'b'
3+
#define CHARR '\0'
4+
#define FLOAT 5.09f
5+
#define FLOAT_EXPR (5 / 1000.0f)
6+
7+
#define INVALID_UTF8 "\xf0\x28\x8c\x28"

tests/headers/macro_str.h

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)