Skip to content

Commit e3649e2

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 rust-lang#283
1 parent 1a8a2ac commit e3649e2

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

libbindgen/src/clang.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ impl Cursor {
487487
}
488488

489489
/// Try to evaluate this cursor.
490-
pub fn evaluate(&self) -> EvalResult {
490+
pub fn evaluate(&self) -> Option<EvalResult> {
491491
EvalResult::new(*self)
492492
}
493493
}
@@ -1306,10 +1306,31 @@ impl EvalResult {
13061306
#[cfg(not(feature = "llvm_stable"))]
13071307
impl EvalResult {
13081308
/// Evaluate `cursor` and return the result.
1309-
pub fn new(cursor: Cursor) -> Self {
1310-
EvalResult {
1311-
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
1309+
pub fn new(cursor: Cursor) -> Option<Self> {
1310+
// Clang has an internal assertion we can trigger if we try to evaluate
1311+
// a cursor containing a variadic template type reference. Triggering
1312+
// the assertion aborts the process, and we don't want that. Clang
1313+
// *also* doesn't expose any API for finding variadic vs non-variadic
1314+
// template type references, let alone whether a type referenced is a
1315+
// template type, instead they seem to show up as type references to an
1316+
// unexposed type. Our solution is to just flat out ban all
1317+
// `CXType_Unexposed` from evaluation.
1318+
let mut found_cant_eval = false;
1319+
cursor.visit(|c| {
1320+
if c.kind() == CXCursor_TypeRef && c.cur_type().kind() == CXType_Unexposed {
1321+
found_cant_eval = true;
1322+
CXChildVisit_Break
1323+
} else {
1324+
CXChildVisit_Recurse
1325+
}
1326+
});
1327+
if found_cant_eval {
1328+
return None;
13121329
}
1330+
1331+
Some(EvalResult {
1332+
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
1333+
})
13131334
}
13141335

13151336
fn kind(&self) -> Enum_CXEvalResultKind {

libbindgen/src/ir/var.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@ impl ClangSubItemParser for Var {
209209
_ => unreachable!(),
210210
};
211211

212-
let mut val =
213-
cursor.evaluate().as_int().map(|val| val as i64);
212+
let mut val = cursor.evaluate()
213+
.and_then(|v| v.as_int())
214+
.map(|val| val as i64);
214215
if val.is_none() || !kind.signedness_matches(val.unwrap()) {
215216
let tu = ctx.translation_unit();
216217
val = get_integer_literal_from_cursor(&cursor, tu);
@@ -225,7 +226,7 @@ impl ClangSubItemParser for Var {
225226
})
226227
} else if is_float {
227228
cursor.evaluate()
228-
.as_double()
229+
.and_then(|v| v.as_double())
229230
.map(VarType::Float)
230231
} else {
231232
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)