Skip to content

Commit 04384c3

Browse files
committed
Do not evaluate variadic template types
This is a workaround for an internal clang assertion that gets triggered if we try to evaluate a variadic template type reference. Fixes #283
1 parent 2a93411 commit 04384c3

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

libbindgen/src/clang.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ impl Cursor {
477477
}
478478

479479
/// Try to evaluate this cursor.
480-
pub fn evaluate(&self) -> EvalResult {
480+
pub fn evaluate(&self) -> Option<EvalResult> {
481481
EvalResult::new(*self)
482482
}
483483
}
@@ -1296,10 +1296,33 @@ impl EvalResult {
12961296
#[cfg(not(feature = "llvm_stable"))]
12971297
impl EvalResult {
12981298
/// Evaluate `cursor` and return the result.
1299-
pub fn new(cursor: Cursor) -> Self {
1300-
EvalResult {
1301-
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
1299+
pub fn new(cursor: Cursor) -> Option<Self> {
1300+
ast_dump(&cursor, 0);
1301+
1302+
// Clang has an internal assertion we can trigger if we try to evaluate
1303+
// a cursor containing a variadic template type reference. Triggering
1304+
// the assertion aborts the process, and we don't want that. Clang
1305+
// *also* doesn't expose any API for finding variadic vs non-variadic
1306+
// template type references, let alone whether a type referenced is a
1307+
// template type, instead they seem to show up as type references to an
1308+
// unexposed type. Our solution is to just flat out ban all
1309+
// `CXType_Unexposed` from evaluation.
1310+
let mut found_cant_eval = false;
1311+
cursor.visit(|c| {
1312+
if c.kind() == CXCursor_TypeRef && c.cur_type().kind() == CXType_Unexposed {
1313+
found_cant_eval = true;
1314+
CXChildVisit_Break
1315+
} else {
1316+
CXChildVisit_Recurse
1317+
}
1318+
});
1319+
if found_cant_eval {
1320+
return None;
13021321
}
1322+
1323+
Some(EvalResult {
1324+
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
1325+
})
13031326
}
13041327

13051328
fn kind(&self) -> Enum_CXEvalResultKind {

libbindgen/src/ir/var.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,12 @@ impl ClangSubItemParser for Var {
205205
// to look at the canonical type of the pointee too, and check
206206
// is char, u8, or i8 I guess).
207207
let value = if is_bool {
208-
cursor.evaluate().as_int()
208+
cursor.evaluate()
209+
.and_then(|v| v.as_int())
209210
.map(|val| VarType::Bool(val != 0))
210211
} else if is_integer {
211212
cursor.evaluate()
212-
.as_int()
213+
.and_then(|v| v.as_int())
213214
.map(|val| val as i64)
214215
.or_else(|| {
215216
let tu = ctx.translation_unit();
@@ -218,7 +219,7 @@ impl ClangSubItemParser for Var {
218219
.map(VarType::Int)
219220
} else if is_float {
220221
cursor.evaluate()
221-
.as_double()
222+
.and_then(|v| v.as_double())
222223
.map(VarType::Float)
223224
} else {
224225
None
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+
#[repr(C)]
8+
#[derive(Debug, Copy, Clone)]
9+
pub struct B<T> {
10+
pub _address: u8,
11+
pub _phantom_0: ::std::marker::PhantomData<T>,
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// bindgen-flags: -- -std=c++11
2+
3+
template <typename... T>
4+
struct B {
5+
// Can't generate anything meaningful in Rust for this, but we shouldn't
6+
// trigger an assertion inside Clang.
7+
static const long c = sizeof...(T);
8+
};

0 commit comments

Comments
 (0)