diff --git a/src/clang.rs b/src/clang.rs index 7da755eaba..5e78848af8 100755 --- a/src/clang.rs +++ b/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 { + pub fn referenced(&self) -> Option { 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(cur: CXCursor, @@ -933,7 +938,9 @@ impl Into 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 } } } @@ -1257,3 +1264,50 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult { pub fn extract_clang_version() -> String { unsafe { clang_getClangVersion().into() } } + +#[derive(Debug)] +pub struct EvalResult { + x: CXEvalResult, +} + +#[cfg(feature = "llvm_stable")] +impl EvalResult { + pub fn new(_: Cursor) -> Self { + EvalResult { + x: ::std::ptr::null_mut(), + } + } + + pub fn as_int(&self) -> Option { + None + } +} + +#[cfg(not(feature = "llvm_stable"))] +impl EvalResult { + pub fn new(cursor: Cursor) -> Self { + EvalResult { + x: unsafe { clang_Cursor_Evaluate(cursor.x) }, + } + } + + pub fn kind(&self) -> Enum_CXEvalResultKind { + unsafe { clang_EvalResult_getKind(self.x) } + } + + pub fn as_int(&self) -> Option { + 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/src/clangll.rs b/src/clangll.rs index b974311769..d44b40335e 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -7,7 +7,18 @@ #![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, 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 +1447,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/src/ir/context.rs b/src/ir/context.rs index 1b446ace16..690b8178d8 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -590,8 +590,7 @@ impl<'ctx> BindgenContext<'ctx> { -> Option { use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization, - CXCursor_TypeAliasTemplateDecl, - CXCursor_TypeRef}; + CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef}; debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", ty, location, diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 59044bdde5..7c13b3dc7a 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -667,7 +667,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 +679,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/src/ir/var.rs b/src/ir/var.rs index 1c7b20280e..a4c6e8de17 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -159,13 +159,23 @@ 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) + let is_integer = 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()) - }); + .map(|t| t.is_integer()) + .unwrap_or(false); + + 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) + }) + } else { + None + }; + let mangling = cursor_mangling(&cursor); diff --git a/tests/expectations/tests/constant-evaluate.rs b/tests/expectations/tests/constant-evaluate.rs new file mode 100644 index 0000000000..ec95301894 --- /dev/null +++ b/tests/expectations/tests/constant-evaluate.rs @@ -0,0 +1,12 @@ +/* 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; diff --git a/tests/headers/constant-evaluate.h b/tests/headers/constant-evaluate.h new file mode 100644 index 0000000000..1c6747a6b2 --- /dev/null +++ b/tests/headers/constant-evaluate.h @@ -0,0 +1,7 @@ + +enum { + foo = 4, + bar = 8, +}; + +const long long BAZ = (1 << foo) | bar;