Skip to content

clang: Evaluate more complex constant expressions in variables. #259

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

Closed
wants to merge 4 commits into from
Closed
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
58 changes: 56 additions & 2 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Cursor> {
pub fn referenced(&self) -> Option<Cursor> {
unsafe {
let ret = Cursor {
x: clang_getCursorReferenced(self.x),
Expand Down Expand Up @@ -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<Visitor>(cur: CXCursor,
Expand Down Expand Up @@ -933,7 +938,9 @@ impl Into<String> 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
}
}
}
Expand Down Expand Up @@ -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<i32> {
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<i32> {
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) };
}
}
25 changes: 24 additions & 1 deletion src/clangll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
3 changes: 1 addition & 2 deletions src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,7 @@ impl<'ctx> BindgenContext<'ctx> {
-> Option<ItemId> {
use clangll::{CXCursor_ClassTemplate,
CXCursor_ClassTemplatePartialSpecialization,
CXCursor_TypeAliasTemplateDecl,
CXCursor_TypeRef};
CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
ty,
location,
Expand Down
4 changes: 2 additions & 2 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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());
Expand Down
22 changes: 16 additions & 6 deletions src/ir/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/tests/constant-evaluate.rs
Original file line number Diff line number Diff line change
@@ -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;
7 changes: 7 additions & 0 deletions tests/headers/constant-evaluate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

enum {
foo = 4,
bar = 8,
};

const long long BAZ = (1 << foo) | bar;