summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2017-01-22 12:58:12 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2017-01-23 10:22:08 +0100
commitb83da2729fc83663f979da05201920e039ae3c3f (patch)
tree27e1c8b1b7f0fef74b064740238da843d4cfc1f6 /src
parent7373a4258f652c23e5fe00ad14740393caa40082 (diff)
Unify under the `bindgen` name.
Diffstat (limited to 'src')
-rw-r--r--src/chooser.rs26
-rw-r--r--src/clang.rs1371
-rw-r--r--src/codegen/helpers.rs190
-rw-r--r--src/codegen/mod.rs2341
-rw-r--r--src/ir/annotations.rs188
-rw-r--r--src/ir/comp.rs962
-rw-r--r--src/ir/context.rs1267
-rw-r--r--src/ir/derive.rs67
-rw-r--r--src/ir/enum_ty.rs183
-rw-r--r--src/ir/function.rs318
-rw-r--r--src/ir/int.rs113
-rw-r--r--src/ir/item.rs1370
-rw-r--r--src/ir/item_kind.rs114
-rw-r--r--src/ir/layout.rs91
-rw-r--r--src/ir/mod.rs19
-rw-r--r--src/ir/module.rs78
-rw-r--r--src/ir/ty.rs926
-rw-r--r--src/ir/type_collector.rs22
-rw-r--r--src/ir/var.rs317
-rw-r--r--src/lib.rs808
-rw-r--r--src/log_stubs.rs30
-rw-r--r--src/main.rs59
-rw-r--r--src/options.rs311
-rw-r--r--src/parse.rs104
-rw-r--r--src/regex_set.rs69
-rw-r--r--src/uses.rs102
26 files changed, 11446 insertions, 0 deletions
diff --git a/src/chooser.rs b/src/chooser.rs
new file mode 100644
index 00000000..51392d70
--- /dev/null
+++ b/src/chooser.rs
@@ -0,0 +1,26 @@
+//! A public API for more fine-grained customization of bindgen behavior.
+
+pub use ir::int::IntKind;
+pub use ir::enum_ty::{EnumVariantValue, EnumVariantCustomBehavior};
+use std::fmt;
+
+/// A trait to allow configuring different kinds of types in different
+/// situations.
+pub trait TypeChooser: fmt::Debug {
+ /// The integer kind an integer macro should have, given a name and the
+ /// value of that macro, or `None` if you want the default to be chosen.
+ fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
+ None
+ }
+
+ /// This function should return whether, given the a given enum variant
+ /// name, and value, returns whether this enum variant will forcibly be a
+ /// constant.
+ fn enum_variant_behavior(&self,
+ _enum_name: Option<&str>,
+ _variant_name: &str,
+ _variant_value: EnumVariantValue)
+ -> Option<EnumVariantCustomBehavior> {
+ None
+ }
+}
diff --git a/src/clang.rs b/src/clang.rs
new file mode 100644
index 00000000..491aaa07
--- /dev/null
+++ b/src/clang.rs
@@ -0,0 +1,1371 @@
+//! A higher level Clang API built on top of the generated bindings in the
+//! `clang_sys` module.
+
+#![allow(non_upper_case_globals, dead_code)]
+
+
+use cexpr;
+use clang_sys::*;
+use std::{mem, ptr, slice};
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::hash::Hash;
+use std::hash::Hasher;
+use std::os::raw::{c_char, c_int, c_uint, c_ulong};
+
+/// A cursor into the Clang AST, pointing to an AST node.
+///
+/// We call the AST node pointed to by the cursor the cursor's "referent".
+#[derive(Copy, Clone)]
+pub struct Cursor {
+ x: CXCursor,
+}
+
+impl fmt::Debug for Cursor {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt,
+ "Cursor({} kind: {}, loc: {}, usr: {:?})",
+ self.spelling(),
+ kind_to_str(self.kind()),
+ self.location(),
+ self.usr())
+ }
+}
+
+impl Cursor {
+ /// Get the Unified Symbol Resolution for this cursor's referent, if
+ /// available.
+ ///
+ /// The USR can be used to compare entities across translation units.
+ pub fn usr(&self) -> Option<String> {
+ let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) };
+ if s.is_empty() { None } else { Some(s) }
+ }
+
+ /// Is this cursor's referent a declaration?
+ pub fn is_declaration(&self) -> bool {
+ unsafe { clang_isDeclaration(self.kind()) != 0 }
+ }
+
+ /// Get the null cursor, which has no referent.
+ pub fn null() -> Self {
+ Cursor {
+ x: unsafe { clang_getNullCursor() },
+ }
+ }
+
+ /// Get this cursor's referent's spelling.
+ pub fn spelling(&self) -> String {
+ unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
+ }
+
+ /// Get this cursor's referent's display name.
+ ///
+ /// This is not necessarily a valid identifier. It includes extra
+ /// information, such as parameters for a function, etc.
+ pub fn display_name(&self) -> String {
+ unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) }
+ }
+
+ /// Get the mangled name of this cursor's referent.
+ pub fn mangling(&self) -> String {
+ unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) }
+ }
+
+ /// Get the `Cursor` for this cursor's referent's lexical parent.
+ ///
+ /// The lexical parent is the parent of the definition. The semantic parent
+ /// is the parent of the declaration. Generally, the lexical parent doesn't
+ /// have any effect on semantics, while the semantic parent does.
+ ///
+ /// In the following snippet, the `Foo` class would be the semantic parent
+ /// of the out-of-line `method` definition, while the lexical parent is the
+ /// translation unit.
+ ///
+ /// ```c++
+ /// class Foo {
+ /// void method();
+ /// };
+ ///
+ /// void Foo::method() { /* ... */ }
+ /// ```
+ pub fn lexical_parent(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getCursorLexicalParent(self.x),
+ }
+ }
+ }
+
+ /// Get the referent's semantic parent, if one is available.
+ ///
+ /// See documentation for `lexical_parent` for details on semantic vs
+ /// lexical parents.
+ pub fn fallible_semantic_parent(&self) -> Option<Cursor> {
+ let sp = unsafe {
+ Cursor {
+ x: clang_getCursorSemanticParent(self.x),
+ }
+ };
+ if sp == *self || !sp.is_valid() {
+ return None;
+ }
+ Some(sp)
+ }
+
+ /// Get the referent's semantic parent.
+ ///
+ /// See documentation for `lexical_parent` for details on semantic vs
+ /// lexical parents.
+ pub fn semantic_parent(&self) -> Cursor {
+ self.fallible_semantic_parent().unwrap()
+ }
+
+ /// Return the number of template arguments used by this cursor's referent,
+ /// if the referent is either a template specialization or
+ /// declaration. Returns -1 otherwise.
+ ///
+ /// NOTE: This may not return `Some` for some non-fully specialized
+ /// templates, see #193 and #194.
+ pub fn num_template_args(&self) -> Option<u32> {
+ let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
+
+ if n >= 0 {
+ Some(n as u32)
+ } else {
+ debug_assert_eq!(n, -1);
+ None
+ }
+ }
+
+ /// Get a cursor pointing to this referent's containing translation unit.
+ ///
+ /// Note that we shouldn't create a `TranslationUnit` struct here, because
+ /// bindgen assumes there will only be one of them alive at a time, and
+ /// disposes it on drop. That can change if this would be required, but I
+ /// think we can survive fine without it.
+ pub fn translation_unit(&self) -> Cursor {
+ assert!(self.is_valid());
+ unsafe {
+ let tu = clang_Cursor_getTranslationUnit(self.x);
+ let cursor = Cursor {
+ x: clang_getTranslationUnitCursor(tu),
+ };
+ assert!(cursor.is_valid());
+ cursor
+ }
+ }
+
+ /// Is the referent a top level construct?
+ pub fn is_toplevel(&self) -> bool {
+ let mut semantic_parent = self.fallible_semantic_parent();
+
+ while semantic_parent.is_some() &&
+ (semantic_parent.unwrap().kind() == CXCursor_Namespace ||
+ semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias ||
+ semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) {
+ semantic_parent = semantic_parent.unwrap()
+ .fallible_semantic_parent();
+ }
+
+ let tu = self.translation_unit();
+ // Yes, this can happen with, e.g., macro definitions.
+ semantic_parent == tu.fallible_semantic_parent()
+ }
+
+ /// There are a few kinds of types that we need to treat specially, mainly
+ /// not tracking the type declaration but the location of the cursor, given
+ /// clang doesn't expose a proper declaration for these types.
+ pub fn is_template_like(&self) -> bool {
+ match self.kind() {
+ CXCursor_ClassTemplate |
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_TypeAliasTemplateDecl => true,
+ _ => false,
+ }
+ }
+
+ /// Get the kind of referent this cursor is pointing to.
+ pub fn kind(&self) -> CXCursorKind {
+ unsafe { clang_getCursorKind(self.x) }
+ }
+
+ /// Is the referent an anonymous record definition?
+ pub fn is_anonymous(&self) -> bool {
+ unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
+ }
+
+ /// Is the referent a template specialization?
+ pub fn is_template(&self) -> bool {
+ self.specialized().is_some()
+ }
+
+ /// Is the referent a fully specialized template specialization without any
+ /// remaining free template arguments?
+ pub fn is_fully_specialized_template(&self) -> bool {
+ self.is_template() && self.num_template_args().unwrap_or(0) > 0
+ }
+
+ /// Is the referent a template specialization that still has remaining free
+ /// template arguments?
+ pub fn is_in_non_fully_specialized_template(&self) -> bool {
+ if self.is_toplevel() {
+ return false;
+ }
+ let parent = self.semantic_parent();
+ (parent.is_template() && !parent.is_fully_specialized_template()) ||
+ parent.is_in_non_fully_specialized_template()
+ }
+
+ /// Is this cursor pointing a valid referent?
+ pub fn is_valid(&self) -> bool {
+ unsafe { clang_isInvalid(self.kind()) == 0 }
+ }
+
+ /// Get the source location for the referent.
+ pub fn location(&self) -> SourceLocation {
+ unsafe {
+ SourceLocation {
+ x: clang_getCursorLocation(self.x),
+ }
+ }
+ }
+
+ /// Get the source location range for the referent.
+ pub fn extent(&self) -> CXSourceRange {
+ unsafe { clang_getCursorExtent(self.x) }
+ }
+
+ /// Get the raw declaration comment for this referent, if one exists.
+ pub fn raw_comment(&self) -> Option<String> {
+ let s = unsafe {
+ cxstring_into_string(clang_Cursor_getRawCommentText(self.x))
+ };
+ if s.is_empty() { None } else { Some(s) }
+ }
+
+ /// Get the referent's parsed comment.
+ pub fn comment(&self) -> Comment {
+ unsafe {
+ Comment {
+ x: clang_Cursor_getParsedComment(self.x),
+ }
+ }
+ }
+
+ /// Get the referent's type.
+ pub fn cur_type(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_getCursorType(self.x),
+ }
+ }
+ }
+
+ /// Given that this cursor's referent is a reference to another type, or is
+ /// a declaration, get the cursor pointing to the referenced type or type of
+ /// the declared thing.
+ pub fn definition(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getCursorDefinition(self.x),
+ };
+
+ if ret.is_valid() { Some(ret) } else { None }
+ }
+ }
+
+ /// Given that this cursor's referent is reference type, get the cursor
+ /// pointing to the referenced type.
+ pub fn referenced(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getCursorReferenced(self.x),
+ };
+
+ if ret.is_valid() { Some(ret) } else { None }
+ }
+ }
+
+ /// Get the canonical cursor for this referent.
+ ///
+ /// Many types can be declared multiple times before finally being properly
+ /// defined. This method allows us to get the canonical cursor for the
+ /// referent type.
+ pub fn canonical(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getCanonicalCursor(self.x),
+ }
+ }
+ }
+
+ /// Given that this cursor points to a template specialization, get a cursor
+ /// pointing to the template definition that is being specialized.
+ pub fn specialized(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getSpecializedCursorTemplate(self.x),
+ };
+ if ret.is_valid() { Some(ret) } else { None }
+ }
+ }
+
+ /// Assuming that this cursor's referent is a template declaration, get the
+ /// kind of cursor that would be generated for its specializations.
+ pub fn template_kind(&self) -> CXCursorKind {
+ unsafe { clang_getTemplateCursorKind(self.x) }
+ }
+
+ /// Traverse this cursor's referent and its children.
+ ///
+ /// Call the given function on each AST node traversed.
+ pub fn visit<Visitor>(&self, mut visitor: Visitor)
+ where Visitor: FnMut(Cursor) -> CXChildVisitResult,
+ {
+ unsafe {
+ clang_visitChildren(self.x,
+ visit_children::<Visitor>,
+ mem::transmute(&mut visitor));
+ }
+ }
+
+ /// Returns whether the given location contains a cursor with the given
+ /// kind in the first level of nesting underneath (doesn't look
+ /// recursively).
+ pub fn contains_cursor(&self, kind: CXCursorKind) -> bool {
+ let mut found = false;
+
+ self.visit(|c| {
+ if c.kind() == kind {
+ found = true;
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+
+ found
+ }
+
+ /// Is the referent an inlined function?
+ pub fn is_inlined_function(&self) -> bool {
+ clang_Cursor_isFunctionInlined::is_loaded() &&
+ unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
+ }
+
+ /// Get the width of this cursor's referent bit field, or `None` if the
+ /// referent is not a bit field.
+ pub fn bit_width(&self) -> Option<u32> {
+ unsafe {
+ let w = clang_getFieldDeclBitWidth(self.x);
+ if w == -1 { None } else { Some(w as u32) }
+ }
+ }
+
+ /// Get the integer representation type used to hold this cursor's referent
+ /// enum type.
+ pub fn enum_type(&self) -> Option<Type> {
+ unsafe {
+ let t = Type {
+ x: clang_getEnumDeclIntegerType(self.x),
+ };
+ if t.is_valid() { Some(t) } else { None }
+ }
+ }
+
+ /// Get the signed constant value for this cursor's enum variant referent.
+ ///
+ /// Returns None if the cursor's referent is not an enum variant.
+ pub fn enum_val_signed(&self) -> Option<i64> {
+ unsafe {
+ if self.kind() == CXCursor_EnumConstantDecl {
+ Some(clang_getEnumConstantDeclValue(self.x) as i64)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Get the unsigned constant value for this cursor's enum variant referent.
+ ///
+ /// Returns None if the cursor's referent is not an enum variant.
+ pub fn enum_val_unsigned(&self) -> Option<u64> {
+ unsafe {
+ if self.kind() == CXCursor_EnumConstantDecl {
+ Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Given that this cursor's referent is a `typedef`, get the `Type` that is
+ /// being aliased.
+ pub fn typedef_type(&self) -> Option<Type> {
+ let inner = Type {
+ x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) },
+ };
+
+ if inner.is_valid() { Some(inner) } else { None }
+ }
+
+ /// Get the linkage kind for this cursor's referent.
+ ///
+ /// This only applies to functions and variables.
+ pub fn linkage(&self) -> CXLinkageKind {
+ unsafe { clang_getCursorLinkage(self.x) }
+ }
+
+ /// Get the visibility of this cursor's referent.
+ pub fn visibility(&self) -> CXVisibilityKind {
+ unsafe { clang_getCursorVisibility(self.x) }
+ }
+
+ /// Given that this cursor's referent is a function, return cursors to its
+ /// parameters.
+ pub fn args(&self) -> Option<Vec<Cursor>> {
+ // XXX: We might want to use and keep num_args
+ // match self.kind() {
+ // CXCursor_FunctionDecl |
+ // CXCursor_CXXMethod => {
+ unsafe {
+ let w = clang_Cursor_getNumArguments(self.x);
+ if w == -1 {
+ None
+ } else {
+ let num = w as u32;
+
+ let mut args = vec![];
+ for i in 0..num {
+ args.push(Cursor {
+ x: clang_Cursor_getArgument(self.x, i as c_uint),
+ });
+ }
+ Some(args)
+ }
+ }
+ }
+
+ /// Given that this cursor's referent is a function/method call or
+ /// declaration, return the number of arguments it takes.
+ ///
+ /// Returns -1 if the cursor's referent is not a function/method call or
+ /// declaration.
+ pub fn num_args(&self) -> Result<u32, ()> {
+ unsafe {
+ let w = clang_Cursor_getNumArguments(self.x);
+ if w == -1 { Err(()) } else { Ok(w as u32) }
+ }
+ }
+
+ /// Get the access specifier for this cursor's referent.
+ pub fn access_specifier(&self) -> CX_CXXAccessSpecifier {
+ unsafe { clang_getCXXAccessSpecifier(self.x) }
+ }
+
+ /// Is this cursor's referent a field declaration that is marked as
+ /// `mutable`?
+ pub fn is_mutable_field(&self) -> bool {
+ unsafe { clang_CXXField_isMutable(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is declared `static`?
+ pub fn method_is_static(&self) -> bool {
+ unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is declared `const`?
+ pub fn method_is_const(&self) -> bool {
+ unsafe { clang_CXXMethod_isConst(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is declared `const`?
+ pub fn method_is_virtual(&self) -> bool {
+ unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a struct or class with virtual members?
+ pub fn is_virtual_base(&self) -> bool {
+ unsafe { clang_isVirtualBase(self.x) != 0 }
+ }
+
+ /// Try to evaluate this cursor.
+ pub fn evaluate(&self) -> Option<EvalResult> {
+ EvalResult::new(*self)
+ }
+}
+
+extern "C" fn visit_children<Visitor>(cur: CXCursor,
+ _parent: CXCursor,
+ data: CXClientData)
+ -> CXChildVisitResult
+ where Visitor: FnMut(Cursor) -> CXChildVisitResult,
+{
+ let func: &mut Visitor = unsafe { mem::transmute(data) };
+ let child = Cursor {
+ x: cur,
+ };
+
+ (*func)(child)
+}
+
+impl PartialEq for Cursor {
+ fn eq(&self, other: &Cursor) -> bool {
+ unsafe { clang_equalCursors(self.x, other.x) == 1 }
+ }
+}
+
+impl Eq for Cursor {}
+
+impl Hash for Cursor {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ unsafe { clang_hashCursor(self.x) }.hash(state)
+ }
+}
+
+/// The type of a node in clang's AST.
+#[derive(Clone)]
+pub struct Type {
+ x: CXType,
+}
+
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ unsafe { clang_equalTypes(self.x, other.x) != 0 }
+ }
+}
+
+impl Eq for Type {}
+
+impl fmt::Debug for Type {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt,
+ "Type({}, kind: {}, decl: {:?}, canon: {:?})",
+ self.spelling(),
+ type_to_str(self.kind()),
+ self.declaration(),
+ self.declaration().canonical())
+ }
+}
+
+/// An error about the layout of a struct, class, or type.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum LayoutError {
+ /// Asked for the layout of an invalid type.
+ Invalid,
+ /// Asked for the layout of an incomplete type.
+ Incomplete,
+ /// Asked for the layout of a dependent type.
+ Dependent,
+ /// Asked for the layout of a type that does not have constant size.
+ NotConstantSize,
+ /// Asked for the layout of a field in a type that does not have such a
+ /// field.
+ InvalidFieldName,
+ /// An unknown layout error.
+ Unknown,
+}
+
+impl ::std::convert::From<i32> for LayoutError {
+ fn from(val: i32) -> Self {
+ use self::LayoutError::*;
+ let val = match CXTypeLayoutError::from_raw(val) {
+ Some(val) => val,
+ None => return Unknown,
+ };
+
+ match val {
+ CXTypeLayoutError_Invalid => Invalid,
+ CXTypeLayoutError_Incomplete => Incomplete,
+ CXTypeLayoutError_Dependent => Dependent,
+ CXTypeLayoutError_NotConstantSize => NotConstantSize,
+ CXTypeLayoutError_InvalidFieldName => InvalidFieldName,
+ _ => Unknown,
+ }
+ }
+}
+
+impl Type {
+ /// Get this type's kind.
+ pub fn kind(&self) -> CXTypeKind {
+ self.x.kind
+ }
+
+ /// Get a cursor pointing to this type's declaration.
+ pub fn declaration(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getTypeDeclaration(self.x),
+ }
+ }
+ }
+
+ /// Get a raw display name for this type.
+ pub fn spelling(&self) -> String {
+ unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }
+ }
+
+ /// Is this type const qualified?
+ pub fn is_const(&self) -> bool {
+ unsafe { clang_isConstQualifiedType(self.x) != 0 }
+ }
+
+ /// What is the size of this type? Paper over invalid types by returning `0`
+ /// for them.
+ pub fn size(&self) -> usize {
+ unsafe {
+ let val = clang_Type_getSizeOf(self.x);
+ if val < 0 { 0 } else { val as usize }
+ }
+ }
+
+ /// What is the size of this type?
+ pub fn fallible_size(&self) -> Result<usize, LayoutError> {
+ let val = unsafe { clang_Type_getSizeOf(self.x) };
+ if val < 0 {
+ Err(LayoutError::from(val as i32))
+ } else {
+ Ok(val as usize)
+ }
+ }
+
+ /// What is the alignment of this type? Paper over invalid types by
+ /// returning `0`.
+ pub fn align(&self) -> usize {
+ unsafe {
+ let val = clang_Type_getAlignOf(self.x);
+ if val < 0 { 0 } else { val as usize }
+ }
+ }
+
+ /// What is the alignment of this type?
+ pub fn fallible_align(&self) -> Result<usize, LayoutError> {
+ unsafe {
+ let val = clang_Type_getAlignOf(self.x);
+ if val < 0 {
+ Err(LayoutError::from(val as i32))
+ } else {
+ Ok(val as usize)
+ }
+ }
+ }
+
+ /// Get the layout for this type, or an error describing why it does not
+ /// have a valid layout.
+ pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> {
+ use ir::layout::Layout;
+ let size = try!(self.fallible_size());
+ let align = try!(self.fallible_align());
+ Ok(Layout::new(size, align))
+ }
+
+ /// If this type is a class template specialization, return its
+ /// template arguments. Otherwise, return None.
+ pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
+ let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
+ if n >= 0 {
+ Some(TypeTemplateArgIterator {
+ x: self.x,
+ length: n as u32,
+ index: 0,
+ })
+ } else {
+ debug_assert_eq!(n, -1);
+ None
+ }
+ }
+
+ /// Given that this type is a pointer type, return the type that it points
+ /// to.
+ pub fn pointee_type(&self) -> Option<Type> {
+ match self.kind() {
+ CXType_Pointer |
+ CXType_RValueReference |
+ CXType_LValueReference |
+ CXType_MemberPointer => {
+ let ret = Type {
+ x: unsafe { clang_getPointeeType(self.x) },
+ };
+ debug_assert!(ret.is_valid());
+ Some(ret)
+ }
+ _ => None,
+ }
+ }
+
+ /// Given that this type is an array, vector, or complex type, return the
+ /// type of its elements.
+ pub fn elem_type(&self) -> Option<Type> {
+ let current_type = Type {
+ x: unsafe { clang_getElementType(self.x) },
+ };
+ if current_type.is_valid() {
+ Some(current_type)
+ } else {
+ None
+ }
+ }
+
+ /// Given that this type is an array or vector type, return its number of
+ /// elements.
+ pub fn num_elements(&self) -> Option<usize> {
+ let num_elements_returned = unsafe { clang_getNumElements(self.x) };
+ if num_elements_returned != -1 {
+ Some(num_elements_returned as usize)
+ } else {
+ None
+ }
+ }
+
+ /// Get the canonical version of this type. This sees through `typdef`s and
+ /// aliases to get the underlying, canonical type.
+ pub fn canonical_type(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_getCanonicalType(self.x),
+ }
+ }
+ }
+
+ /// Is this type a variadic function type?
+ pub fn is_variadic(&self) -> bool {
+ unsafe { clang_isFunctionTypeVariadic(self.x) != 0 }
+ }
+
+ /// Given that this type is a function type, get the type of its return
+ /// value.
+ pub fn ret_type(&self) -> Option<Type> {
+ let rt = Type {
+ x: unsafe { clang_getResultType(self.x) },
+ };
+ if rt.is_valid() { Some(rt) } else { None }
+ }
+
+ /// Given that this type is a function type, get its calling convention. If
+ /// this is not a function type, `CXCallingConv_Invalid` is returned.
+ pub fn call_conv(&self) -> CXCallingConv {
+ unsafe { clang_getFunctionTypeCallingConv(self.x) }
+ }
+
+ /// For elaborated types (types which use `class`, `struct`, or `union` to
+ /// disambiguate types from local bindings), get the underlying type.
+ pub fn named(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_Type_getNamedType(self.x),
+ }
+ }
+ }
+
+ /// Is this a valid type?
+ pub fn is_valid(&self) -> bool {
+ self.kind() != CXType_Invalid
+ }
+
+ /// Is this a valid and exposed type?
+ pub fn is_valid_and_exposed(&self) -> bool {
+ self.is_valid() && self.kind() != CXType_Unexposed
+ }
+
+ /// Is this type a fully specialized template?
+ pub fn is_fully_specialized_template(&self) -> bool {
+ // Yep, the spelling of this containing type-parameter is extremely
+ // nasty... But can happen in <type_traits>. Unfortunately I couldn't
+ // reduce it enough :(
+ !self.spelling().contains("type-parameter") &&
+ self.template_args()
+ .map_or(false, |mut args| {
+ args.len() > 0 &&
+ !args.any(|t| t.spelling().contains("type-parameter"))
+ })
+ }
+}
+
+/// An iterator for a type's template arguments.
+pub struct TypeTemplateArgIterator {
+ x: CXType,
+ length: u32,
+ index: u32,
+}
+
+impl Iterator for TypeTemplateArgIterator {
+ type Item = Type;
+ fn next(&mut self) -> Option<Type> {
+ if self.index < self.length {
+ let idx = self.index as c_uint;
+ self.index += 1;
+ Some(Type {
+ x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+impl ExactSizeIterator for TypeTemplateArgIterator {
+ fn len(&self) -> usize {
+ assert!(self.index <= self.length);
+ (self.length - self.index) as usize
+ }
+}
+
+/// A `SourceLocation` is a file, line, column, and byte offset location for
+/// some source text.
+pub struct SourceLocation {
+ x: CXSourceLocation,
+}
+
+impl SourceLocation {
+ /// Get the (file, line, column, byte offset) tuple for this source
+ /// location.
+ pub fn location(&self) -> (File, usize, usize, usize) {
+ unsafe {
+ let mut file = mem::zeroed();
+ let mut line = 0;
+ let mut col = 0;
+ let mut off = 0;
+ clang_getSpellingLocation(self.x,
+ &mut file,
+ &mut line,
+ &mut col,
+ &mut off);
+ (File {
+ x: file,
+ },
+ line as usize,
+ col as usize,
+ off as usize)
+ }
+ }
+}
+
+impl fmt::Display for SourceLocation {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let (file, line, col, _) = self.location();
+ if let Some(name) = file.name() {
+ write!(f, "{}:{}:{}", name, line, col)
+ } else {
+ "builtin definitions".fmt(f)
+ }
+ }
+}
+
+/// A comment in the source text.
+///
+/// Comments are sort of parsed by Clang, and have a tree structure.
+pub struct Comment {
+ x: CXComment,
+}
+
+impl Comment {
+ /// What kind of comment is this?
+ pub fn kind(&self) -> CXCommentKind {
+ unsafe { clang_Comment_getKind(self.x) }
+ }
+
+ /// Get this comment's children comment
+ pub fn get_children(&self) -> CommentChildrenIterator {
+ CommentChildrenIterator {
+ parent: self.x,
+ length: unsafe { clang_Comment_getNumChildren(self.x) },
+ index: 0,
+ }
+ }
+
+ /// Given that this comment is the start or end of an HTML tag, get its tag
+ /// name.
+ pub fn get_tag_name(&self) -> String {
+ unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) }
+ }
+
+ /// Given that this comment is an HTML start tag, get its attributes.
+ pub fn get_tag_attrs(&self) -> CommentAttributesIterator {
+ CommentAttributesIterator {
+ x: self.x,
+ length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
+ index: 0,
+ }
+ }
+}
+
+/// An iterator for a comment's children
+pub struct CommentChildrenIterator {
+ parent: CXComment,
+ length: c_uint,
+ index: c_uint,
+}
+
+impl Iterator for CommentChildrenIterator {
+ type Item = Comment;
+ fn next(&mut self) -> Option<Comment> {
+ if self.index < self.length {
+ let idx = self.index;
+ self.index += 1;
+ Some(Comment {
+ x: unsafe { clang_Comment_getChild(self.parent, idx) },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+/// An HTML start tag comment attribute
+pub struct CommentAttribute {
+ /// HTML start tag attribute name
+ pub name: String,
+ /// HTML start tag attribute value
+ pub value: String,
+}
+
+/// An iterator for a comment's attributes
+pub struct CommentAttributesIterator {
+ x: CXComment,
+ length: c_uint,
+ index: c_uint,
+}
+
+impl Iterator for CommentAttributesIterator {
+ type Item = CommentAttribute;
+ fn next(&mut self) -> Option<CommentAttribute> {
+ if self.index < self.length {
+ let idx = self.index;
+ self.index += 1;
+ Some(CommentAttribute {
+ name: unsafe {
+ cxstring_into_string(
+ clang_HTMLStartTag_getAttrName(self.x, idx))
+ },
+ value: unsafe {
+ cxstring_into_string(
+ clang_HTMLStartTag_getAttrValue(self.x, idx))
+ },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+/// A source file.
+pub struct File {
+ x: CXFile,
+}
+
+impl File {
+ /// Get the name of this source file.
+ pub fn name(&self) -> Option<String> {
+ if self.x.is_null() {
+ return None;
+ }
+ Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) })
+ }
+}
+
+fn cxstring_into_string(s: CXString) -> String {
+ if s.data.is_null() {
+ return "".to_owned();
+ }
+ unsafe {
+ let c_str = CStr::from_ptr(clang_getCString(s) as *const _);
+ let ret = c_str.to_string_lossy().into_owned();
+ clang_disposeString(s);
+ ret
+ }
+}
+
+/// An `Index` is an environment for a set of translation units that will
+/// typically end up linked together in one final binary.
+pub struct Index {
+ x: CXIndex,
+}
+
+impl Index {
+ /// Construct a new `Index`.
+ ///
+ /// The `pch` parameter controls whether declarations in pre-compiled
+ /// headers are included when enumerating a translation unit's "locals".
+ ///
+ /// The `diag` parameter controls whether debugging diagnostics are enabled.
+ pub fn new(pch: bool, diag: bool) -> Index {
+ unsafe {
+ Index {
+ x: clang_createIndex(pch as c_int, diag as c_int),
+ }
+ }
+ }
+}
+
+impl fmt::Debug for Index {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Index {{ }}")
+ }
+}
+
+impl Drop for Index {
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeIndex(self.x);
+ }
+ }
+}
+
+/// A token emitted by clang's lexer.
+#[derive(Debug)]
+pub struct Token {
+ /// The kind of token this is.
+ pub kind: CXTokenKind,
+ /// A display name for this token.
+ pub spelling: String,
+}
+
+/// A translation unit (or "compilation unit").
+pub struct TranslationUnit {
+ x: CXTranslationUnit,
+}
+
+impl fmt::Debug for TranslationUnit {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "TranslationUnit {{ }}")
+ }
+}
+
+impl TranslationUnit {
+ /// Parse a source file into a translation unit.
+ pub fn parse(ix: &Index,
+ file: &str,
+ cmd_args: &[String],
+ unsaved: &[UnsavedFile],
+ opts: CXTranslationUnit_Flags)
+ -> Option<TranslationUnit> {
+ let fname = CString::new(file).unwrap();
+ let _c_args: Vec<CString> =
+ cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect();
+ let c_args: Vec<*const c_char> =
+ _c_args.iter().map(|s| s.as_ptr()).collect();
+ let mut c_unsaved: Vec<CXUnsavedFile> =
+ unsaved.iter().map(|f| f.x).collect();
+ let tu = unsafe {
+ clang_parseTranslationUnit(ix.x,
+ fname.as_ptr(),
+ c_args.as_ptr(),
+ c_args.len() as c_int,
+ c_unsaved.as_mut_ptr(),
+ c_unsaved.len() as c_uint,
+ opts)
+ };
+ if tu.is_null() {
+ None
+ } else {
+ Some(TranslationUnit {
+ x: tu,
+ })
+ }
+ }
+
+ /// Get the Clang diagnostic information associated with this translation
+ /// unit.
+ pub fn diags(&self) -> Vec<Diagnostic> {
+ unsafe {
+ let num = clang_getNumDiagnostics(self.x) as usize;
+ let mut diags = vec![];
+ for i in 0..num {
+ diags.push(Diagnostic {
+ x: clang_getDiagnostic(self.x, i as c_uint),
+ });
+ }
+ diags
+ }
+ }
+
+ /// Get a cursor pointing to the root of this translation unit's AST.
+ pub fn cursor(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getTranslationUnitCursor(self.x),
+ }
+ }
+ }
+
+ /// Is this the null translation unit?
+ pub fn is_null(&self) -> bool {
+ self.x.is_null()
+ }
+
+ /// Invoke Clang's lexer on this translation unit and get the stream of
+ /// tokens that come out.
+ pub fn tokens(&self, cursor: &Cursor) -> Option<Vec<Token>> {
+ let range = cursor.extent();
+ let mut tokens = vec![];
+ unsafe {
+ let mut token_ptr = ptr::null_mut();
+ let mut num_tokens: c_uint = 0;
+ clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens);
+ if token_ptr.is_null() {
+ return None;
+ }
+
+ let token_array = slice::from_raw_parts(token_ptr,
+ num_tokens as usize);
+ for &token in token_array.iter() {
+ let kind = clang_getTokenKind(token);
+ let spelling =
+ cxstring_into_string(clang_getTokenSpelling(self.x, token));
+
+ tokens.push(Token {
+ kind: kind,
+ spelling: spelling,
+ });
+ }
+ clang_disposeTokens(self.x, token_ptr, num_tokens);
+ }
+ Some(tokens)
+ }
+
+ /// Convert a set of tokens from clang into `cexpr` tokens, for further
+ /// processing.
+ pub fn cexpr_tokens(&self,
+ cursor: &Cursor)
+ -> Option<Vec<cexpr::token::Token>> {
+ use cexpr::token;
+
+ let mut tokens = match self.tokens(cursor) {
+ Some(tokens) => tokens,
+ None => return None,
+ };
+
+ // FIXME(emilio): LLVM 3.9 at least always include an extra token for no
+ // good reason (except if we're at EOF). So we do this kind of hack,
+ // where we skip known-to-cause problems trailing punctuation and
+ // trailing keywords.
+ //
+ // This is sort of unfortunate, though :(.
+ //
+ // I'll try to get it fixed in LLVM if I have the time to submit a
+ // patch.
+ let mut trim_last_token = false;
+ if let Some(token) = tokens.last() {
+ // The starting of the next macro.
+ trim_last_token |= token.spelling == "#" &&
+ token.kind == CXToken_Punctuation;
+
+ // A following keyword of any kind, like a following declaration.
+ trim_last_token |= token.kind == CXToken_Keyword;
+ }
+
+ if trim_last_token {
+ tokens.pop().unwrap();
+ }
+
+ Some(tokens.into_iter()
+ .filter_map(|token| {
+ let kind = match token.kind {
+ CXToken_Punctuation => token::Kind::Punctuation,
+ CXToken_Literal => token::Kind::Literal,
+ CXToken_Identifier => token::Kind::Identifier,
+ CXToken_Keyword => token::Kind::Keyword,
+ // NB: cexpr is not too happy about comments inside
+ // expressions, so we strip them down here.
+ CXToken_Comment => return None,
+ _ => {
+ panic!("Found unexpected token kind: {:?}", token.kind)
+ }
+ };
+
+ Some(token::Token {
+ kind: kind,
+ raw: token.spelling.into_bytes().into_boxed_slice(),
+ })
+ })
+ .collect::<Vec<_>>())
+ }
+}
+
+impl Drop for TranslationUnit {
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeTranslationUnit(self.x);
+ }
+ }
+}
+
+
+/// A diagnostic message generated while parsing a translation unit.
+pub struct Diagnostic {
+ x: CXDiagnostic,
+}
+
+impl Diagnostic {
+ /// Format this diagnostic message as a string, using the given option bit
+ /// flags.
+ pub fn format(&self) -> String {
+ unsafe {
+ let opts = clang_defaultDiagnosticDisplayOptions();
+ cxstring_into_string(clang_formatDiagnostic(self.x, opts))
+ }
+ }
+
+ /// What is the severity of this diagnostic message?
+ pub fn severity(&self) -> CXDiagnosticSeverity {
+ unsafe { clang_getDiagnosticSeverity(self.x) }
+ }
+}
+
+impl Drop for Diagnostic {
+ /// Destroy this diagnostic message.
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeDiagnostic(self.x);
+ }
+ }
+}
+
+/// A file which has not been saved to disk.
+pub struct UnsavedFile {
+ x: CXUnsavedFile,
+ name: CString,
+ contents: CString,
+}
+
+impl UnsavedFile {
+ /// Construct a new unsaved file with the given `name` and `contents`.
+ pub fn new(name: &str, contents: &str) -> UnsavedFile {
+ let name = CString::new(name).unwrap();
+ let contents = CString::new(contents).unwrap();
+ let x = CXUnsavedFile {
+ Filename: name.as_ptr(),
+ Contents: contents.as_ptr(),
+ Length: contents.as_bytes().len() as c_ulong,
+ };
+ UnsavedFile {
+ x: x,
+ name: name,
+ contents: contents,
+ }
+ }
+}
+
+/// Convert a cursor kind into a static string.
+pub fn kind_to_str(x: CXCursorKind) -> String {
+ unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
+}
+
+/// Convert a type kind to a static string.
+pub fn type_to_str(x: CXTypeKind) -> String {
+ unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
+}
+
+/// Dump the Clang AST to stdout for debugging purposes.
+pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
+ fn print_indent(depth: isize, s: &str) {
+ for _ in 0..depth {
+ print!("\t");
+ }
+ println!("{}", s);
+ }
+
+ print_indent(depth,
+ &format!("(kind: {}, spelling: {}, type: {}",
+ kind_to_str(c.kind()),
+ c.spelling(),
+ type_to_str(c.cur_type().kind())));
+
+ // Recurse.
+ c.visit(|s| ast_dump(&s, depth + 1));
+
+ print_indent(depth, ")");
+
+ CXChildVisit_Continue
+}
+
+/// Try to extract the clang version to a string
+pub fn extract_clang_version() -> String {
+ unsafe { cxstring_into_string(clang_getClangVersion()) }
+}
+
+/// A wrapper for the result of evaluating an expression.
+#[derive(Debug)]
+pub struct EvalResult {
+ x: CXEvalResult,
+}
+
+impl EvalResult {
+ /// Evaluate `cursor` and return the result.
+ pub fn new(cursor: Cursor) -> Option<Self> {
+ if !clang_Cursor_Evaluate::is_loaded() {
+ return None;
+ }
+
+ // Clang has an internal assertion we can trigger if we try to evaluate
+ // a cursor containing a variadic template type reference. Triggering
+ // the assertion aborts the process, and we don't want that. Clang
+ // *also* doesn't expose any API for finding variadic vs non-variadic
+ // template type references, let alone whether a type referenced is a
+ // template type, instead they seem to show up as type references to an
+ // unexposed type. Our solution is to just flat out ban all
+ // `CXType_Unexposed` from evaluation.
+ let mut found_cant_eval = false;
+ cursor.visit(|c| {
+ if c.kind() == CXCursor_TypeRef &&
+ c.cur_type().kind() == CXType_Unexposed {
+ found_cant_eval = true;
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Recurse
+ }
+ });
+ if found_cant_eval {
+ return None;
+ }
+
+ Some(EvalResult {
+ x: unsafe { clang_Cursor_Evaluate(cursor.x) },
+ })
+ }
+
+ fn kind(&self) -> CXEvalResultKind {
+ unsafe { clang_EvalResult_getKind(self.x) }
+ }
+
+ /// Try to get back the result as a double.
+ pub fn as_double(&self) -> Option<f64> {
+ match self.kind() {
+ CXEval_Float => {
+ Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
+ }
+ _ => None,
+ }
+ }
+
+ /// Try to get back the result as an integer.
+ pub fn as_int(&self) -> Option<i32> {
+ match self.kind() {
+ CXEval_Int => {
+ Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32)
+ }
+ _ => None,
+ }
+ }
+
+ /// Evaluates the expression as a literal string, that may or may not be
+ /// valid utf-8.
+ pub fn as_literal_string(&self) -> Option<Vec<u8>> {
+ match self.kind() {
+ CXEval_StrLiteral => {
+ let ret = unsafe {
+ CStr::from_ptr(clang_EvalResult_getAsStr(self.x))
+ };
+ Some(ret.to_bytes().to_vec())
+ }
+ _ => None,
+ }
+ }
+}
+
+impl Drop for EvalResult {
+ fn drop(&mut self) {
+ unsafe { clang_EvalResult_dispose(self.x) };
+ }
+}
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
new file mode 100644
index 00000000..06dadab0
--- /dev/null
+++ b/src/codegen/helpers.rs
@@ -0,0 +1,190 @@
+//! Helpers for code generation that don't need macro expansion.
+
+use aster;
+use ir::layout::Layout;
+use syntax::ast;
+use syntax::ptr::P;
+
+
+pub mod attributes {
+ use aster;
+ use syntax::ast;
+
+ pub fn repr(which: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
+ }
+
+ pub fn repr_list(which_ones: &[&str]) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("repr").words(which_ones).build()
+ }
+
+ pub fn derives(which_ones: &[&str]) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("derive").words(which_ones).build()
+ }
+
+ pub fn inline() -> ast::Attribute {
+ aster::AstBuilder::new().attr().word("inline")
+ }
+
+ pub fn doc(comment: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().doc(comment)
+ }
+
+ pub fn link_name(name: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().name_value("link_name").str(name)
+ }
+}
+
+/// Generates a proper type for a field or type with a given `Layout`, that is,
+/// a type with the correct size and alignment restrictions.
+pub struct BlobTyBuilder {
+ layout: Layout,
+}
+
+impl BlobTyBuilder {
+ pub fn new(layout: Layout) -> Self {
+ BlobTyBuilder {
+ layout: layout,
+ }
+ }
+
+ pub fn build(self) -> P<ast::Ty> {
+ let opaque = self.layout.opaque();
+
+ // FIXME(emilio, #412): We fall back to byte alignment, but there are
+ // some things that legitimately are more than 8-byte aligned.
+ //
+ // Eventually we should be able to `unwrap` here, but...
+ let ty_name = match opaque.known_rust_type_for_array() {
+ Some(ty) => ty,
+ None => {
+ warn!("Found unknown alignment on code generation!");
+ "u8"
+ }
+ };
+
+ let data_len = opaque.array_size().unwrap_or(self.layout.size);
+
+ let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build();
+ if data_len == 1 {
+ inner_ty
+ } else {
+ aster::ty::TyBuilder::new().array(data_len).build(inner_ty)
+ }
+ }
+}
+
+pub mod ast_ty {
+ use aster;
+ use ir::context::BindgenContext;
+ use ir::function::FunctionSig;
+ use ir::ty::FloatKind;
+ use syntax::ast;
+ use syntax::ptr::P;
+
+ pub fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
+ let ident = ctx.rust_ident_raw(&name);
+ match ctx.options().ctypes_prefix {
+ Some(ref prefix) => {
+ let prefix = ctx.rust_ident_raw(prefix);
+ quote_ty!(ctx.ext_cx(), $prefix::$ident)
+ }
+ None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident),
+ }
+ }
+
+ pub fn float_kind_rust_type(ctx: &BindgenContext,
+ fk: FloatKind)
+ -> P<ast::Ty> {
+ // TODO: we probably should just take the type layout into
+ // account?
+ //
+ // Also, maybe this one shouldn't be the default?
+ //
+ // FIXME: `c_longdouble` doesn't seem to be defined in some
+ // systems, so we use `c_double` directly.
+ match (fk, ctx.options().convert_floats) {
+ (FloatKind::Float, true) => aster::ty::TyBuilder::new().f32(),
+ (FloatKind::Double, true) |
+ (FloatKind::LongDouble, true) => aster::ty::TyBuilder::new().f64(),
+ (FloatKind::Float, false) => raw_type(ctx, "c_float"),
+ (FloatKind::Double, false) |
+ (FloatKind::LongDouble, false) => raw_type(ctx, "c_double"),
+ (FloatKind::Float128, _) => {
+ aster::ty::TyBuilder::new().array(16).u8()
+ }
+ }
+ }
+
+ pub fn int_expr(val: i64) -> P<ast::Expr> {
+ use std::i64;
+ let expr = aster::AstBuilder::new().expr();
+
+ // This is not representable as an i64 if it's negative, so we
+ // special-case it.
+ //
+ // Fix in aster incoming.
+ if val == i64::MIN {
+ expr.neg().uint(1u64 << 63)
+ } else {
+ expr.int(val)
+ }
+ }
+
+ pub fn bool_expr(val: bool) -> P<ast::Expr> {
+ aster::AstBuilder::new().expr().bool(val)
+ }
+
+ pub fn byte_array_expr(bytes: &[u8]) -> P<ast::Expr> {
+ let mut vec = Vec::with_capacity(bytes.len() + 1);
+ for byte in bytes {
+ vec.push(int_expr(*byte as i64));
+ }
+ vec.push(int_expr(0));
+
+ let kind = ast::ExprKind::Vec(vec);
+
+ aster::AstBuilder::new().expr().build_expr_kind(kind)
+ }
+
+ pub fn cstr_expr(mut string: String) -> P<ast::Expr> {
+ string.push('\0');
+ aster::AstBuilder::new()
+ .expr()
+ .build_lit(aster::AstBuilder::new().lit().byte_str(string))
+ }
+
+ pub fn float_expr(f: f64) -> P<ast::Expr> {
+ use aster::symbol::ToSymbol;
+ let mut string = f.to_string();
+
+ // So it gets properly recognised as a floating point constant.
+ if !string.contains('.') {
+ string.push('.');
+ }
+
+ let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol());
+ aster::AstBuilder::new().expr().lit().build_lit(kind)
+ }
+
+ pub fn arguments_from_signature(signature: &FunctionSig,
+ ctx: &BindgenContext)
+ -> Vec<P<ast::Expr>> {
+ // TODO: We need to keep in sync the argument names, so we should unify
+ // this with the other loop that decides them.
+ let mut unnamed_arguments = 0;
+ signature.argument_types()
+ .iter()
+ .map(|&(ref name, _ty)| {
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+ aster::expr::ExprBuilder::new().id(arg_name)
+ })
+ .collect::<Vec<_>>()
+ }
+}
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
new file mode 100644
index 00000000..7451dd11
--- /dev/null
+++ b/src/codegen/mod.rs
@@ -0,0 +1,2341 @@
+mod helpers;
+
+use aster;
+
+use ir::annotations::FieldAccessorKind;
+use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind};
+use ir::context::{BindgenContext, ItemId};
+use ir::derive::{CanDeriveCopy, CanDeriveDebug};
+use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
+use ir::function::{Function, FunctionSig};
+use ir::int::IntKind;
+use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath};
+use ir::item_kind::ItemKind;
+use ir::layout::Layout;
+use ir::module::Module;
+use ir::ty::{Type, TypeKind};
+use ir::type_collector::ItemSet;
+use ir::var::Var;
+use self::helpers::{BlobTyBuilder, attributes};
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::collections::{HashSet, VecDeque};
+use std::collections::hash_map::{Entry, HashMap};
+use std::fmt::Write;
+use std::iter;
+use std::mem;
+use std::ops;
+use syntax::abi::Abi;
+use syntax::ast;
+use syntax::codemap::{Span, respan};
+use syntax::ptr::P;
+
+fn root_import(ctx: &BindgenContext, module: &Item) -> P<ast::Item> {
+ assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up");
+ assert!(module.is_module());
+
+ let root = ctx.root_module().canonical_name(ctx);
+ let root_ident = ctx.rust_ident(&root);
+
+ let super_ = aster::AstBuilder::new().id("super");
+ let supers = module.ancestors(ctx)
+ .filter(|id| ctx.resolve_item(*id).is_module())
+ .map(|_| super_.clone())
+ .chain(iter::once(super_));
+
+ let self_ = iter::once(aster::AstBuilder::new().id("self"));
+ let root_ident = iter::once(root_ident);
+
+ let path = self_.chain(supers).chain(root_ident);
+
+ let use_root = aster::AstBuilder::new()
+ .item()
+ .use_()
+ .ids(path)
+ .build()
+ .build();
+
+ quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap()
+}
+
+struct CodegenResult<'a> {
+ items: Vec<P<ast::Item>>,
+
+ /// A monotonic counter used to add stable unique id's to stuff that doesn't
+ /// need to be referenced by anything.
+ codegen_id: &'a Cell<usize>,
+
+ /// Whether an union has been generated at least once.
+ saw_union: bool,
+
+ items_seen: HashSet<ItemId>,
+ /// The set of generated function/var names, needed because in C/C++ is
+ /// legal to do something like:
+ ///
+ /// ```c++
+ /// extern "C" {
+ /// void foo();
+ /// extern int bar;
+ /// }
+ ///
+ /// extern "C" {
+ /// void foo();
+ /// extern int bar;
+ /// }
+ /// ```
+ ///
+ /// Being these two different declarations.
+ functions_seen: HashSet<String>,
+ vars_seen: HashSet<String>,
+
+ /// Used for making bindings to overloaded functions. Maps from a canonical
+ /// function name to the number of overloads we have already codegen'd for
+ /// that name. This lets us give each overload a unique suffix.
+ overload_counters: HashMap<String, u32>,
+}
+
+impl<'a> CodegenResult<'a> {
+ fn new(codegen_id: &'a Cell<usize>) -> Self {
+ CodegenResult {
+ items: vec![],
+ saw_union: false,
+ codegen_id: codegen_id,
+ items_seen: Default::default(),
+ functions_seen: Default::default(),
+ vars_seen: Default::default(),
+ overload_counters: Default::default(),
+ }
+ }
+
+ fn next_id(&mut self) -> usize {
+ self.codegen_id.set(self.codegen_id.get() + 1);
+ self.codegen_id.get()
+ }
+
+ fn saw_union(&mut self) {
+ self.saw_union = true;
+ }
+
+ fn seen(&self, item: ItemId) -> bool {
+ self.items_seen.contains(&item)
+ }
+
+ fn set_seen(&mut self, item: ItemId) {
+ self.items_seen.insert(item);
+ }
+
+ fn seen_function(&self, name: &str) -> bool {
+ self.functions_seen.contains(name)
+ }
+
+ fn saw_function(&mut self, name: &str) {
+ self.functions_seen.insert(name.into());
+ }
+
+ /// Get the overload number for the given function name. Increments the
+ /// counter internally so the next time we ask for the overload for this
+ /// name, we get the incremented value, and so on.
+ fn overload_number(&mut self, name: &str) -> u32 {
+ let mut counter =
+ self.overload_counters.entry(name.into()).or_insert(0);
+ let number = *counter;
+ *counter += 1;
+ number
+ }
+
+ fn seen_var(&self, name: &str) -> bool {
+ self.vars_seen.contains(name)
+ }
+
+ fn saw_var(&mut self, name: &str) {
+ self.vars_seen.insert(name.into());
+ }
+
+ fn inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>>
+ where F: FnOnce(&mut Self),
+ {
+ let mut new = Self::new(self.codegen_id);
+
+ cb(&mut new);
+
+ self.saw_union |= new.saw_union;
+
+ new.items
+ }
+}
+
+impl<'a> ops::Deref for CodegenResult<'a> {
+ type Target = Vec<P<ast::Item>>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.items
+ }
+}
+
+impl<'a> ops::DerefMut for CodegenResult<'a> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.items
+ }
+}
+
+struct ForeignModBuilder {
+ inner: ast::ForeignMod,
+}
+
+impl ForeignModBuilder {
+ fn new(abi: Abi) -> Self {
+ ForeignModBuilder {
+ inner: ast::ForeignMod {
+ abi: abi,
+ items: vec![],
+ },
+ }
+ }
+
+ fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self {
+ self.inner.items.push(item);
+ self
+ }
+
+ #[allow(dead_code)]
+ fn with_foreign_items<I>(mut self, items: I) -> Self
+ where I: IntoIterator<Item = ast::ForeignItem>,
+ {
+ self.inner.items.extend(items.into_iter());
+ self
+ }
+
+ fn build(self, ctx: &BindgenContext) -> P<ast::Item> {
+ use syntax::codemap::DUMMY_SP;
+ P(ast::Item {
+ ident: ctx.rust_ident(""),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::ForeignMod(self.inner),
+ vis: ast::Visibility::Public,
+ attrs: vec![],
+ span: DUMMY_SP,
+ })
+ }
+}
+
+/// A trait to convert a rust type into a pointer, optionally const, to the same
+/// type.
+///
+/// This is done due to aster's lack of pointer builder, I guess I should PR
+/// there.
+trait ToPtr {
+ fn to_ptr(self, is_const: bool, span: Span) -> P<ast::Ty>;
+}
+
+impl ToPtr for P<ast::Ty> {
+ fn to_ptr(self, is_const: bool, span: Span) -> Self {
+ let ty = ast::TyKind::Ptr(ast::MutTy {
+ ty: self,
+ mutbl: if is_const {
+ ast::Mutability::Immutable
+ } else {
+ ast::Mutability::Mutable
+ },
+ });
+ P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ty,
+ span: span,
+ })
+ }
+}
+
+trait CodeGenerator {
+ /// Extra information from the caller.
+ type Extra;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ extra: &Self::Extra);
+}
+
+impl CodeGenerator for Item {
+ type Extra = ();
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ _extra: &()) {
+ if self.is_hidden(ctx) || result.seen(self.id()) {
+ debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
+ self = {:?}", self);
+ return;
+ }
+
+ debug!("<Item as CodeGenerator>::codegen: self = {:?}", self);
+
+ result.set_seen(self.id());
+
+ match *self.kind() {
+ ItemKind::Module(ref module) => {
+ module.codegen(ctx, result, whitelisted_items, self);
+ }
+ ItemKind::Function(ref fun) => {
+ if ctx.options().codegen_config.functions {
+ fun.codegen(ctx, result, whitelisted_items, self);
+ }
+ }
+ ItemKind::Var(ref var) => {
+ if ctx.options().codegen_config.vars {
+ var.codegen(ctx, result, whitelisted_items, self);
+ }
+ }
+ ItemKind::Type(ref ty) => {
+ if ctx.options().codegen_config.types {
+ ty.codegen(ctx, result, whitelisted_items, self);
+ }
+ }
+ }
+ }
+}
+
+impl CodeGenerator for Module {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ item: &Item) {
+ debug!("<Module as CodeGenerator>::codegen: item = {:?}", item);
+
+ let codegen_self = |result: &mut CodegenResult,
+ found_any: &mut bool| {
+ for child in self.children() {
+ if whitelisted_items.contains(child) {
+ *found_any = true;
+ ctx.resolve_item(*child)
+ .codegen(ctx, result, whitelisted_items, &());
+ }
+ }
+
+ if item.id() == ctx.root_module() {
+ let saw_union = result.saw_union;
+ if saw_union && !ctx.options().unstable_rust {
+ utils::prepend_union_types(ctx, &mut *result);
+ }
+ if ctx.need_bindegen_complex_type() {
+ utils::prepend_complex_type(ctx, &mut *result);
+ }
+ }
+ };
+
+ if !ctx.options().enable_cxx_namespaces ||
+ (self.is_inline() && !ctx.options().conservative_inline_namespaces) {
+ codegen_self(result, &mut false);
+ return;
+ }
+
+ let mut found_any = false;
+ let inner_items = result.inner(|result| {
+ result.push(root_import(ctx, item));
+ codegen_self(result, &mut found_any);
+ });
+
+ // Don't bother creating an empty module.
+ if !found_any {
+ return;
+ }
+
+ let module = ast::ItemKind::Mod(ast::Mod {
+ inner: ctx.span(),
+ items: inner_items,
+ });
+
+ let name = item.canonical_name(ctx);
+ let item = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .build_item_kind(name, module);
+
+ result.push(item);
+ }
+}
+
+impl CodeGenerator for Var {
+ type Extra = Item;
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ _whitelisted_items: &ItemSet,
+ item: &Item) {
+ use ir::var::VarType;
+ debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
+
+ let canonical_name = item.canonical_name(ctx);
+
+ if result.seen_var(&canonical_name) {
+ return;
+ }
+ result.saw_var(&canonical_name);
+
+ let ty = self.ty().to_rust_ty(ctx);
+
+ if let Some(val) = self.val() {
+ let const_item = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .const_(canonical_name)
+ .expr();
+ let item = match *val {
+ VarType::Bool(val) => {
+ const_item.build(helpers::ast_ty::bool_expr(val))
+ .build(ty)
+ }
+ VarType::Int(val) => {
+ const_item.build(helpers::ast_ty::int_expr(val)).build(ty)
+ }
+ VarType::String(ref bytes) => {
+ // Account the trailing zero.
+ //
+ // TODO: Here we ignore the type we just made up, probably
+ // we should refactor how the variable type and ty id work.
+ let len = bytes.len() + 1;
+ let ty = quote_ty!(ctx.ext_cx(), [u8; $len]);
+
+ match String::from_utf8(bytes.clone()) {
+ Ok(string) => {
+ const_item.build(helpers::ast_ty::cstr_expr(string))
+ .build(quote_ty!(ctx.ext_cx(), &'static $ty))
+ }
+ Err(..) => {
+ const_item
+ .build(helpers::ast_ty::byte_array_expr(bytes))
+ .build(ty)
+ }
+ }
+ }
+ VarType::Float(f) => {
+ const_item.build(helpers::ast_ty::float_expr(f))
+ .build(ty)
+ }
+ VarType::Char(c) => {
+ const_item
+ .build(aster::AstBuilder::new().expr().lit().byte(c))
+ .build(ty)
+ }
+ };
+
+ result.push(item);
+ } else {
+ let mut attrs = vec![];
+ if let Some(mangled) = self.mangled_name() {
+ attrs.push(attributes::link_name(mangled));
+ } else if canonical_name != self.name() {
+ attrs.push(attributes::link_name(self.name()));
+ }
+
+ let item = ast::ForeignItem {
+ ident: ctx.rust_ident_raw(&canonical_name),
+ attrs: attrs,
+ node: ast::ForeignItemKind::Static(ty, !self.is_const()),
+ id: ast::DUMMY_NODE_ID,
+ span: ctx.span(),
+ vis: ast::Visibility::Public,
+ };
+
+ let item = ForeignModBuilder::new(Abi::C)
+ .with_foreign_item(item)
+ .build(ctx);
+ result.push(item);
+ }
+ }
+}
+
+impl CodeGenerator for Type {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ item: &Item) {
+ debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
+
+ match *self.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Array(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::BlockPointer |
+ TypeKind::Reference(..) |
+ TypeKind::TemplateRef(..) |
+ TypeKind::Function(..) |
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::Named(..) => {
+ // These items don't need code generation, they only need to be
+ // converted to rust types in fields, arguments, and such.
+ return;
+ }
+ TypeKind::Comp(ref ci) => {
+ ci.codegen(ctx, result, whitelisted_items, item)
+ }
+ // NB: The code below will pick the correct
+ // applicable_template_args.
+ TypeKind::TemplateAlias(ref spelling, inner, _) |
+ TypeKind::Alias(ref spelling, inner) => {
+ let inner_item = ctx.resolve_item(inner);
+ let name = item.canonical_name(ctx);
+
+ // Try to catch the common pattern:
+ //
+ // typedef struct foo { ... } foo;
+ //
+ // here.
+ //
+ if inner_item.canonical_name(ctx) == name {
+ return;
+ }
+
+ // If this is a known named type, disallow generating anything
+ // for it too.
+ if utils::type_from_named(ctx, spelling, inner).is_some() {
+ return;
+ }
+
+ let mut applicable_template_args =
+ item.applicable_template_args(ctx);
+ let inner_rust_type = if item.is_opaque(ctx) {
+ applicable_template_args.clear();
+ // Pray if there's no layout.
+ let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
+ BlobTyBuilder::new(layout).build()
+ } else {
+ inner_item.to_rust_ty(ctx)
+ };
+
+ let rust_name = ctx.rust_ident(&name);
+ let mut typedef = aster::AstBuilder::new().item().pub_();
+
+ if let Some(comment) = item.comment() {
+ typedef = typedef.attr().doc(comment);
+ }
+
+ // We prefer using `pub use` over `pub type` because of:
+ // https://github.com/rust-lang/rust/issues/26264
+ let simple_enum_path = match inner_rust_type.node {
+ ast::TyKind::Path(None, ref p) => {
+ if applicable_template_args.is_empty() &&
+ !inner_item.expect_type().canonical_type(ctx).is_builtin_or_named() &&
+ p.segments.iter().all(|p| p.parameters.is_none()) {
+ Some(p.clone())
+ } else {
+ None
+ }
+ },
+ _ => None,
+ };
+
+ let typedef = if let Some(mut p) = simple_enum_path {
+ if p.segments.len() == 1 {
+ p.segments.insert(0, ast::PathSegment {
+ identifier: ctx.ext_cx().ident_of("self"),
+ parameters: None,
+ });
+ }
+ typedef.use_().build(p).as_(rust_name)
+ } else {
+ let mut generics = typedef.type_(rust_name).generics();
+ for template_arg in applicable_template_args.iter() {
+ let template_arg = ctx.resolve_type(*template_arg);
+ if template_arg.is_named() {
+ let name = template_arg.name().unwrap();
+ if name.contains("typename ") {
+ warn!("Item contained `typename`'d template \
+ parameter: {:?}", item);
+ return;
+ }
+ generics =
+ generics.ty_param_id(template_arg.name().unwrap());
+ }
+ }
+ generics.build().build_ty(inner_rust_type)
+ };
+ result.push(typedef)
+ }
+ TypeKind::Enum(ref ei) => {
+ ei.codegen(ctx, result, whitelisted_items, item)
+ }
+ ref u @ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing {:?}!", u)
+ }
+ }
+ }
+}
+
+struct Vtable<'a> {
+ item_id: ItemId,
+ #[allow(dead_code)]
+ methods: &'a [Method],
+ #[allow(dead_code)]
+ base_classes: &'a [Base],
+}
+
+impl<'a> Vtable<'a> {
+ fn new(item_id: ItemId,
+ methods: &'a [Method],
+ base_classes: &'a [Base])
+ -> Self {
+ Vtable {
+ item_id: item_id,
+ methods: methods,
+ base_classes: base_classes,
+ }
+ }
+}
+
+impl<'a> CodeGenerator for Vtable<'a> {
+ type Extra = Item;
+
+ fn codegen<'b>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'b>,
+ _whitelisted_items: &ItemSet,
+ item: &Item) {
+ assert_eq!(item.id(), self.item_id);
+ // For now, generate an empty struct, later we should generate function
+ // pointers and whatnot.
+ let vtable = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .with_attr(attributes::repr("C"))
+ .struct_(self.canonical_name(ctx))
+ .build();
+ result.push(vtable);
+ }
+}
+
+impl<'a> ItemCanonicalName for Vtable<'a> {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx))
+ }
+}
+
+impl<'a> ItemToRustTy for Vtable<'a> {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ aster::ty::TyBuilder::new().id(self.canonical_name(ctx))
+ }
+}
+
+struct Bitfield<'a> {
+ index: usize,
+ fields: Vec<&'a Field>,
+}
+
+impl<'a> Bitfield<'a> {
+ fn new(index: usize, fields: Vec<&'a Field>) -> Self {
+ Bitfield {
+ index: index,
+ fields: fields,
+ }
+ }
+
+ fn codegen_fields(self,
+ ctx: &BindgenContext,
+ fields: &mut Vec<ast::StructField>,
+ methods: &mut Vec<ast::ImplItem>) {
+ use aster::struct_field::StructFieldBuilder;
+ use std::cmp;
+ let mut total_width = self.fields
+ .iter()
+ .fold(0u32, |acc, f| acc + f.bitfield().unwrap());
+
+ if !total_width.is_power_of_two() || total_width < 8 {
+ total_width = cmp::max(8, total_width.next_power_of_two());
+ }
+ debug_assert_eq!(total_width % 8, 0);
+ let total_width_in_bytes = total_width as usize / 8;
+
+ let bitfield_type =
+ BlobTyBuilder::new(Layout::new(total_width_in_bytes,
+ total_width_in_bytes))
+ .build();
+ let field_name = format!("_bitfield_{}", self.index);
+ let field_ident = ctx.ext_cx().ident_of(&field_name);
+ let field = StructFieldBuilder::named(&field_name)
+ .pub_()
+ .build_ty(bitfield_type.clone());
+ fields.push(field);
+
+
+ let mut offset = 0;
+ for field in self.fields {
+ let width = field.bitfield().unwrap();
+ let field_name = field.name()
+ .map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("at_offset_{}", offset));
+
+ let field_item = ctx.resolve_item(field.ty());
+ let field_ty_layout = field_item.kind()
+ .expect_type()
+ .layout(ctx)
+ .expect("Bitfield without layout? Gah!");
+
+ let field_type = field_item.to_rust_ty(ctx);
+ let int_type = BlobTyBuilder::new(field_ty_layout).build();
+
+ let getter_name = ctx.rust_ident(&field_name);
+ let setter_name = ctx.ext_cx()
+ .ident_of(&format!("set_{}", &field_name));
+ let mask = ((1usize << width) - 1) << offset;
+ let prefix = ctx.trait_prefix();
+ // The transmute is unfortunate, but it's needed for enums in
+ // bitfields.
+ let item = quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> $field_type {
+ unsafe {
+ ::$prefix::mem::transmute(
+ (
+ (self.$field_ident &
+ ($mask as $bitfield_type))
+ >> $offset
+ ) as $int_type
+ )
+ }
+ }
+
+ #[inline]
+ pub fn $setter_name(&mut self, val: $field_type) {
+ self.$field_ident &= !($mask as $bitfield_type);
+ self.$field_ident |=
+ (val as $int_type as $bitfield_type << $offset) &
+ ($mask as $bitfield_type);
+ }
+ }
+ )
+ .unwrap();
+
+ let items = match item.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, items) => items,
+ _ => unreachable!(),
+ };
+
+ methods.extend(items.into_iter());
+ offset += width;
+ }
+ }
+}
+
+impl CodeGenerator for CompInfo {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ item: &Item) {
+ use aster::struct_field::StructFieldBuilder;
+
+ debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
+
+ // Don't output classes with template parameters that aren't types, and
+ // also don't output template specializations, neither total or partial.
+ if self.has_non_type_template_params() {
+ return;
+ }
+
+ if self.is_template_specialization() {
+ let layout = item.kind().expect_type().layout(ctx);
+
+ if let Some(layout) = layout {
+ let fn_name = format!("__bindgen_test_layout_template_{}",
+ result.next_id());
+ let fn_name = ctx.rust_ident_raw(&fn_name);
+ let ident = item.to_rust_ty(ctx);
+ let prefix = ctx.trait_prefix();
+ let size_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::size_of::<$ident>());
+ let align_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::align_of::<$ident>());
+ let size = layout.size;
+ let align = layout.align;
+ let item = quote_item!(ctx.ext_cx(),
+ #[test]
+ fn $fn_name() {
+ assert_eq!($size_of_expr, $size);
+ assert_eq!($align_of_expr, $align);
+ })
+ .unwrap();
+ result.push(item);
+ }
+ return;
+ }
+
+ let applicable_template_args = item.applicable_template_args(ctx);
+
+ let mut attributes = vec![];
+ let mut needs_clone_impl = false;
+ if let Some(comment) = item.comment() {
+ attributes.push(attributes::doc(comment));
+ }
+ if self.packed() {
+ attributes.push(attributes::repr_list(&["C", "packed"]));
+ } else {
+ attributes.push(attributes::repr("C"));
+ }
+
+ let is_union = self.kind() == CompKind::Union;
+ let mut derives = vec![];
+ if item.can_derive_debug(ctx, ()) {
+ derives.push("Debug");
+ }
+
+ if item.can_derive_copy(ctx, ()) &&
+ !item.annotations().disallow_copy() {
+ derives.push("Copy");
+ if !applicable_template_args.is_empty() {
+ // FIXME: This requires extra logic if you have a big array in a
+ // templated struct. The reason for this is that the magic:
+ // fn clone(&self) -> Self { *self }
+ // doesn't work for templates.
+ //
+ // It's not hard to fix though.
+ derives.push("Clone");
+ } else {
+ needs_clone_impl = true;
+ }
+ }
+
+ if !derives.is_empty() {
+ attributes.push(attributes::derives(&derives))
+ }
+
+ let mut template_args_used =
+ vec![false; applicable_template_args.len()];
+ let canonical_name = item.canonical_name(ctx);
+ let builder = if is_union && ctx.options().unstable_rust {
+ aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .with_attrs(attributes)
+ .union_(&canonical_name)
+ } else {
+ aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .with_attrs(attributes)
+ .struct_(&canonical_name)
+ };
+
+ // Generate the vtable from the method list if appropriate.
+ //
+ // TODO: I don't know how this could play with virtual methods that are
+ // not in the list of methods found by us, we'll see. Also, could the
+ // order of the vtable pointers vary?
+ //
+ // FIXME: Once we generate proper vtables, we need to codegen the
+ // vtable, but *not* generate a field for it in the case that
+ // needs_explicit_vtable is false but has_vtable is true.
+ //
+ // Also, we need to generate the vtable in such a way it "inherits" from
+ // the parent too.
+ let mut fields = vec![];
+ if self.needs_explicit_vtable(ctx) {
+ let vtable =
+ Vtable::new(item.id(), self.methods(), self.base_members());
+ vtable.codegen(ctx, result, whitelisted_items, item);
+
+ let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span());
+
+ let vtable_field = StructFieldBuilder::named("vtable_")
+ .pub_()
+ .build_ty(vtable_type);
+
+ fields.push(vtable_field);
+ }
+
+ for (i, base) in self.base_members().iter().enumerate() {
+ // Virtual bases are already taken into account by the vtable
+ // pointer.
+ //
+ // FIXME(emilio): Is this always right?
+ if base.is_virtual() {
+ continue;
+ }
+
+ let base_ty = ctx.resolve_type(base.ty);
+ // NB: We won't include unsized types in our base chain because they
+ // would contribute to our size given the dummy field we insert for
+ // unsized types.
+ if base_ty.is_unsized(ctx) {
+ continue;
+ }
+
+ for (i, ty_id) in applicable_template_args.iter().enumerate() {
+ let template_arg_ty = ctx.resolve_type(*ty_id);
+ if base_ty.signature_contains_named_type(ctx, template_arg_ty) {
+ template_args_used[i] = true;
+ }
+ }
+
+ let inner = base.ty.to_rust_ty(ctx);
+ let field_name = if i == 0 {
+ "_base".into()
+ } else {
+ format!("_base_{}", i)
+ };
+
+ let field = StructFieldBuilder::named(field_name)
+ .pub_()
+ .build_ty(inner);
+ fields.push(field);
+ }
+ if is_union {
+ result.saw_union();
+ }
+
+ let layout = item.kind().expect_type().layout(ctx);
+
+ let mut current_bitfield_width = None;
+ let mut current_bitfield_layout: Option<Layout> = None;
+ let mut current_bitfield_fields = vec![];
+ let mut bitfield_count = 0;
+ let struct_fields = self.fields();
+ let fields_should_be_private = item.annotations()
+ .private_fields()
+ .unwrap_or(false);
+ let struct_accessor_kind = item.annotations()
+ .accessor_kind()
+ .unwrap_or(FieldAccessorKind::None);
+
+ let mut methods = vec![];
+ let mut anonymous_field_count = 0;
+ for field in struct_fields {
+ debug_assert_eq!(current_bitfield_width.is_some(),
+ current_bitfield_layout.is_some());
+ debug_assert_eq!(current_bitfield_width.is_some(),
+ !current_bitfield_fields.is_empty());
+
+ let field_ty = ctx.resolve_type(field.ty());
+
+ // Try to catch a bitfield contination early.
+ if let (Some(ref mut bitfield_width), Some(width)) =
+ (current_bitfield_width, field.bitfield()) {
+ let layout = current_bitfield_layout.unwrap();
+ debug!("Testing bitfield continuation {} {} {:?}",
+ *bitfield_width, width, layout);
+ if *bitfield_width + width <= (layout.size * 8) as u32 {
+ *bitfield_width += width;
+ current_bitfield_fields.push(field);
+ continue;
+ }
+ }
+
+ // Flush the current bitfield.
+ if current_bitfield_width.is_some() {
+ debug_assert!(!current_bitfield_fields.is_empty());
+ let bitfield_fields =
+ mem::replace(&mut current_bitfield_fields, vec![]);
+ bitfield_count += 1;
+ Bitfield::new(bitfield_count, bitfield_fields)
+ .codegen_fields(ctx, &mut fields, &mut methods);
+ current_bitfield_width = None;
+ current_bitfield_layout = None;
+ }
+ debug_assert!(current_bitfield_fields.is_empty());
+
+ if let Some(width) = field.bitfield() {
+ let layout = field_ty.layout(ctx)
+ .expect("Bitfield type without layout?");
+ current_bitfield_width = Some(width);
+ current_bitfield_layout = Some(layout);
+ current_bitfield_fields.push(field);
+ continue;
+ }
+
+ for (i, ty_id) in applicable_template_args.iter().enumerate() {
+ let template_arg = ctx.resolve_type(*ty_id);
+ if field_ty.signature_contains_named_type(ctx, template_arg) {
+ template_args_used[i] = true;
+ }
+ }
+
+ let ty = field.ty().to_rust_ty(ctx);
+
+ // NB: In unstable rust we use proper `union` types.
+ let ty = if is_union && !ctx.options().unstable_rust {
+ if ctx.options().enable_cxx_namespaces {
+ quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>)
+ } else {
+ quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
+ }
+ } else {
+ ty
+ };
+
+ let mut attrs = vec![];
+ if let Some(comment) = field.comment() {
+ attrs.push(attributes::doc(comment));
+ }
+ let field_name = match field.name() {
+ Some(name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ anonymous_field_count += 1;
+ format!("__bindgen_anon_{}", anonymous_field_count)
+ }
+ };
+
+ let is_private = field.annotations()
+ .private_fields()
+ .unwrap_or(fields_should_be_private);
+
+ let accessor_kind = field.annotations()
+ .accessor_kind()
+ .unwrap_or(struct_accessor_kind);
+
+ let mut field = StructFieldBuilder::named(&field_name);
+
+ if !is_private {
+ field = field.pub_();
+ }
+
+ let field = field.with_attrs(attrs)
+ .build_ty(ty.clone());
+
+ fields.push(field);
+
+ // TODO: Factor the following code out, please!
+ if accessor_kind == FieldAccessorKind::None {
+ continue;
+ }
+
+ let getter_name =
+ ctx.rust_ident_raw(&format!("get_{}", field_name));
+ let mutable_getter_name =
+ ctx.rust_ident_raw(&format!("get_{}_mut", field_name));
+ let field_name = ctx.rust_ident_raw(&field_name);
+
+ let accessor_methods_impl = match accessor_kind {
+ FieldAccessorKind::None => unreachable!(),
+ FieldAccessorKind::Regular => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+
+ #[inline]
+ pub fn $mutable_getter_name(&mut self) -> &mut $ty {
+ &mut self.$field_name
+ }
+ }
+ )
+ }
+ FieldAccessorKind::Unsafe => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub unsafe fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+
+ #[inline]
+ pub unsafe fn $mutable_getter_name(&mut self)
+ -> &mut $ty {
+ &mut self.$field_name
+ }
+ }
+ )
+ }
+ FieldAccessorKind::Immutable => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+ }
+ )
+ }
+ };
+
+ match accessor_methods_impl.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, ref items) => {
+ methods.extend(items.clone())
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // Flush the last bitfield if any.
+ //
+ // FIXME: Reduce duplication with the loop above.
+ // FIXME: May need to pass current_bitfield_layout too.
+ if current_bitfield_width.is_some() {
+ debug_assert!(!current_bitfield_fields.is_empty());
+ let bitfield_fields = mem::replace(&mut current_bitfield_fields,
+ vec![]);
+ bitfield_count += 1;
+ Bitfield::new(bitfield_count, bitfield_fields)
+ .codegen_fields(ctx, &mut fields, &mut methods);
+ }
+ debug_assert!(current_bitfield_fields.is_empty());
+
+ if is_union && !ctx.options().unstable_rust {
+ let layout = layout.expect("Unable to get layout information?");
+ let ty = BlobTyBuilder::new(layout).build();
+ let field = StructFieldBuilder::named("bindgen_union_field")
+ .pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+
+ // Yeah, sorry about that.
+ if item.is_opaque(ctx) {
+ fields.clear();
+ methods.clear();
+ for i in 0..template_args_used.len() {
+ template_args_used[i] = false;
+ }
+
+ match layout {
+ Some(l) => {
+ let ty = BlobTyBuilder::new(l).build();
+ let field =
+ StructFieldBuilder::named("_bindgen_opaque_blob")
+ .pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+ None => {
+ warn!("Opaque type without layout! Expect dragons!");
+ }
+ }
+ }
+
+ // C requires every struct to be addressable, so what C compilers do is
+ // making the struct 1-byte sized.
+ //
+ // NOTE: This check is conveniently here to avoid the dummy fields we
+ // may add for unused template parameters.
+ if self.is_unsized(ctx) {
+ let ty = BlobTyBuilder::new(Layout::new(1, 1)).build();
+ let field = StructFieldBuilder::named("_address")
+ .pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+
+ // Append any extra template arguments that nobody has used so far.
+ for (i, ty) in applicable_template_args.iter().enumerate() {
+ if !template_args_used[i] {
+ let name = ctx.resolve_type(*ty).name().unwrap();
+ let ident = ctx.rust_ident(name);
+ let prefix = ctx.trait_prefix();
+ let phantom = quote_ty!(ctx.ext_cx(),
+ ::$prefix::marker::PhantomData<$ident>);
+ let field =
+ StructFieldBuilder::named(format!("_phantom_{}", i))
+ .pub_()
+ .build_ty(phantom);
+ fields.push(field)
+ }
+ }
+
+
+ let mut generics = aster::AstBuilder::new().generics();
+ for template_arg in applicable_template_args.iter() {
+ // Take into account that here only arrive named types, not
+ // template specialisations that would need to be
+ // instantiated.
+ //
+ // TODO: Add template args from the parent, here and in
+ // `to_rust_ty`!!
+ let template_arg = ctx.resolve_type(*template_arg);
+ generics = generics.ty_param_id(template_arg.name().unwrap());
+ }
+
+ let generics = generics.build();
+
+ let rust_struct = builder.with_generics(generics.clone())
+ .with_fields(fields)
+ .build();
+ result.push(rust_struct);
+
+ // Generate the inner types and all that stuff.
+ //
+ // TODO: In the future we might want to be smart, and use nested
+ // modules, and whatnot.
+ for ty in self.inner_types() {
+ let child_item = ctx.resolve_item(*ty);
+ // assert_eq!(child_item.parent_id(), item.id());
+ child_item.codegen(ctx, result, whitelisted_items, &());
+ }
+
+ // NOTE: Some unexposed attributes (like alignment attributes) may
+ // affect layout, so we're bad and pray to the gods for avoid sending
+ // all the tests to shit when parsing things like max_align_t.
+ if self.found_unknown_attr() {
+ warn!("Type {} has an unkown attribute that may affect layout",
+ canonical_name);
+ }
+
+ if applicable_template_args.is_empty() && !self.found_unknown_attr() {
+ for var in self.inner_vars() {
+ ctx.resolve_item(*var)
+ .codegen(ctx, result, whitelisted_items, &());
+ }
+
+ if let Some(layout) = layout {
+ let fn_name = format!("bindgen_test_layout_{}", canonical_name);
+ let fn_name = ctx.rust_ident_raw(&fn_name);
+ let ident = ctx.rust_ident_raw(&canonical_name);
+ let prefix = ctx.trait_prefix();
+ let size_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::size_of::<$ident>());
+ let align_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::align_of::<$ident>());
+ let size = layout.size;
+ let align = layout.align;
+ let item = quote_item!(ctx.ext_cx(),
+ #[test]
+ fn $fn_name() {
+ assert_eq!($size_of_expr, $size);
+ assert_eq!($align_of_expr, $align);
+ })
+ .unwrap();
+ result.push(item);
+ }
+
+ let mut method_names = Default::default();
+ if ctx.options().codegen_config.methods {
+ for method in self.methods() {
+ assert!(method.kind() != MethodKind::Constructor);
+ method.codegen_method(ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ whitelisted_items,
+ self);
+ }
+ }
+
+ if ctx.options().codegen_config.constructors {
+ for sig in self.constructors() {
+ Method::new(MethodKind::Constructor,
+ *sig,
+ /* const */
+ false)
+ .codegen_method(ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ whitelisted_items,
+ self);
+ }
+ }
+ }
+
+ // NB: We can't use to_rust_ty here since for opaque types this tries to
+ // use the specialization knowledge to generate a blob field.
+ let ty_for_impl =
+ aster::AstBuilder::new().ty().path().id(&canonical_name).build();
+ if needs_clone_impl {
+ let impl_ = quote_item!(ctx.ext_cx(),
+ impl X {
+ fn clone(&self) -> Self { *self }
+ }
+ );
+
+ let impl_ = match impl_.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(),
+ _ => unreachable!(),
+ };
+
+ let clone_impl = aster::AstBuilder::new()
+ .item()
+ .impl_()
+ .trait_()
+ .id("Clone")
+ .build()
+ .with_generics(generics.clone())
+ .with_items(impl_)
+ .build_ty(ty_for_impl.clone());
+
+ result.push(clone_impl);
+ }
+
+ if !methods.is_empty() {
+ let methods = aster::AstBuilder::new()
+ .item()
+ .impl_()
+ .with_generics(generics)
+ .with_items(methods)
+ .build_ty(ty_for_impl);
+ result.push(methods);
+ }
+ }
+}
+
+trait MethodCodegen {
+ fn codegen_method<'a>(&self,
+ ctx: &BindgenContext,
+ methods: &mut Vec<ast::ImplItem>,
+ method_names: &mut HashMap<String, usize>,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ parent: &CompInfo);
+}
+
+impl MethodCodegen for Method {
+ fn codegen_method<'a>(&self,
+ ctx: &BindgenContext,
+ methods: &mut Vec<ast::ImplItem>,
+ method_names: &mut HashMap<String, usize>,
+ result: &mut CodegenResult<'a>,
+ whitelisted_items: &ItemSet,
+ _parent: &CompInfo) {
+ if self.is_virtual() {
+ return; // FIXME
+ }
+ // First of all, output the actual function.
+ let function_item = ctx.resolve_item(self.signature());
+ function_item.codegen(ctx, result, whitelisted_items, &());
+
+ let function = function_item.expect_function();
+ let signature_item = ctx.resolve_item(function.signature());
+ let mut name = match self.kind() {
+ MethodKind::Constructor => "new".into(),
+ _ => function.name().to_owned(),
+ };
+
+ let signature = match *signature_item.expect_type().kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How in the world?"),
+ };
+
+ // Do not generate variadic methods, since rust does not allow
+ // implementing them, and we don't do a good job at it anyway.
+ if signature.is_variadic() {
+ return;
+ }
+
+ let count = {
+ let mut count = method_names.entry(name.clone())
+ .or_insert(0);
+ *count += 1;
+ *count - 1
+ };
+
+ if count != 0 {
+ name.push_str(&count.to_string());
+ }
+
+ let function_name = function_item.canonical_name(ctx);
+ let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item)
+ .unwrap();
+ if !self.is_static() && !self.is_constructor() {
+ let mutability = if self.is_const() {
+ ast::Mutability::Immutable
+ } else {
+ ast::Mutability::Mutable
+ };
+
+ assert!(!fndecl.inputs.is_empty());
+
+ // FIXME: use aster here.
+ fndecl.inputs[0] = ast::Arg {
+ ty: P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::TyKind::Rptr(None, ast::MutTy {
+ ty: P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::TyKind::ImplicitSelf,
+ span: ctx.span()
+ }),
+ mutbl: mutability,
+ }),
+ span: ctx.span(),
+ }),
+ pat: P(ast::Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::PatKind::Ident(
+ ast::BindingMode::ByValue(ast::Mutability::Immutable),
+ respan(ctx.span(), ctx.ext_cx().ident_of("self")),
+ None
+ ),
+ span: ctx.span(),
+ }),
+ id: ast::DUMMY_NODE_ID,
+ };
+ }
+
+ // If it's a constructor, we always return `Self`, and we inject the
+ // "this" parameter, so there's no need to ask the user for it.
+ //
+ // Note that constructors in Clang are represented as functions with
+ // return-type = void.
+ if self.is_constructor() {
+ fndecl.inputs.remove(0);
+ fndecl.output =
+ ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self));
+ }
+
+ let sig = ast::MethodSig {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: Abi::Rust,
+ decl: P(fndecl),
+ generics: ast::Generics::default(),
+ constness: respan(ctx.span(), ast::Constness::NotConst),
+ };
+
+ let mut exprs = helpers::ast_ty::arguments_from_signature(&signature,
+ ctx);
+
+ let mut stmts = vec![];
+
+ // If it's a constructor, we need to insert an extra parameter with a
+ // variable called `__bindgen_tmp` we're going to create.
+ if self.is_constructor() {
+ let tmp_variable_decl =
+ quote_stmt!(ctx.ext_cx(),
+ let mut __bindgen_tmp = ::std::mem::uninitialized())
+ .unwrap();
+ stmts.push(tmp_variable_decl);
+ exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp);
+ } else if !self.is_static() {
+ assert!(!exprs.is_empty());
+ exprs[0] = if self.is_const() {
+ quote_expr!(ctx.ext_cx(), &*self)
+ } else {
+ quote_expr!(ctx.ext_cx(), &mut *self)
+ };
+ };
+
+ let call = aster::expr::ExprBuilder::new()
+ .call()
+ .id(function_name)
+ .with_args(exprs)
+ .build();
+
+ stmts.push(ast::Stmt {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::StmtKind::Expr(call),
+ span: ctx.span(),
+ });
+
+ if self.is_constructor() {
+ stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap());
+ }
+
+ let block = ast::Block {
+ stmts: stmts,
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span(),
+ };
+
+ let mut attrs = vec![];
+ attrs.push(attributes::inline());
+
+ let item = ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.rust_ident(&name),
+ vis: ast::Visibility::Public,
+ attrs: attrs,
+ node: ast::ImplItemKind::Method(sig, P(block)),
+ defaultness: ast::Defaultness::Final,
+ span: ctx.span(),
+ };
+
+ methods.push(item);
+ }
+}
+
+/// A helper type to construct enums, either bitfield ones or rust-style ones.
+enum EnumBuilder<'a> {
+ Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>),
+ Bitfield {
+ canonical_name: &'a str,
+ aster: P<ast::Item>,
+ },
+}
+
+impl<'a> EnumBuilder<'a> {
+ /// Create a new enum given an item builder, a canonical name, a name for
+ /// the representation, and whether it should be represented as a rust enum.
+ fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>,
+ name: &'a str,
+ repr_name: &str,
+ is_rust: bool)
+ -> Self {
+ if is_rust {
+ EnumBuilder::Rust(aster.enum_(name))
+ } else {
+ EnumBuilder::Bitfield {
+ canonical_name: name,
+ aster: aster.tuple_struct(name)
+ .field()
+ .pub_()
+ .ty()
+ .id(repr_name)
+ .build(),
+ }
+ }
+ }
+
+ /// Add a variant to this enum.
+ fn with_variant<'b>(self,
+ ctx: &BindgenContext,
+ variant: &EnumVariant,
+ mangling_prefix: Option<&String>,
+ rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult<'b>)
+ -> Self {
+ let variant_name = ctx.rust_mangle(variant.name());
+ let expr = aster::AstBuilder::new().expr();
+ let expr = match variant.val() {
+ EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v),
+ EnumVariantValue::Unsigned(v) => expr.uint(v),
+ };
+
+ match self {
+ EnumBuilder::Rust(b) => {
+ EnumBuilder::Rust(b.with_variant_(ast::Variant_ {
+ name: ctx.rust_ident(&*variant_name),
+ attrs: vec![],
+ data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
+ disr_expr: Some(expr),
+ }))
+ }
+ EnumBuilder::Bitfield { canonical_name, .. } => {
+ let constant_name = match mangling_prefix {
+ Some(prefix) => {
+ Cow::Owned(format!("{}_{}", prefix, variant_name))
+ }
+ None => variant_name,
+ };
+
+ let constant = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .const_(&*constant_name)
+ .expr()
+ .call()
+ .id(canonical_name)
+ .arg()
+ .build(expr)
+ .build()
+ .build(rust_ty);
+ result.push(constant);
+ self
+ }
+ }
+ }
+
+ fn build<'b>(self,
+ ctx: &BindgenContext,
+ rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult<'b>)
+ -> P<ast::Item> {
+ match self {
+ EnumBuilder::Rust(b) => b.build(),
+ EnumBuilder::Bitfield { canonical_name, aster } => {
+ let rust_ty_name = ctx.rust_ident_raw(canonical_name);
+ let prefix = ctx.trait_prefix();
+
+ let impl_ = quote_item!(ctx.ext_cx(),
+ impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, other: Self) -> Self {
+ $rust_ty_name(self.0 | other.0)
+ }
+ }
+ )
+ .unwrap();
+
+ result.push(impl_);
+ aster
+ }
+ }
+ }
+}
+
+impl CodeGenerator for Enum {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ _whitelisted_items: &ItemSet,
+ item: &Item) {
+ debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
+
+ let name = item.canonical_name(ctx);
+ let enum_ty = item.expect_type();
+ let layout = enum_ty.layout(ctx);
+
+ let repr = self.repr().map(|repr| ctx.resolve_type(repr));
+ let repr = match repr {
+ Some(repr) => {
+ match *repr.canonical_type(ctx).kind() {
+ TypeKind::Int(int_kind) => int_kind,
+ _ => panic!("Unexpected type as enum repr"),
+ }
+ }
+ None => {
+ warn!("Guessing type of enum! Forward declarations of enums \
+ shouldn't be legal!");
+ IntKind::Int
+ }
+ };
+
+ let signed = repr.is_signed();
+ let size = layout.map(|l| l.size)
+ .or_else(|| repr.known_size())
+ .unwrap_or(0);
+
+ let repr_name = match (signed, size) {
+ (true, 1) => "i8",
+ (false, 1) => "u8",
+ (true, 2) => "i16",
+ (false, 2) => "u16",
+ (true, 4) => "i32",
+ (false, 4) => "u32",
+ (true, 8) => "i64",
+ (false, 8) => "u64",
+ _ => {
+ warn!("invalid enum decl: signed: {}, size: {}", signed, size);
+ "i32"
+ }
+ };
+
+ let mut builder = aster::AstBuilder::new().item().pub_();
+
+ let is_bitfield = {
+ ctx.options().bitfield_enums.matches(&name) ||
+ (enum_ty.name().is_none() &&
+ self.variants()
+ .iter()
+ .any(|v| ctx.options().bitfield_enums.matches(&v.name())))
+ };
+
+ let is_rust_enum = !is_bitfield;
+
+ // FIXME: Rust forbids repr with empty enums. Remove this condition when
+ // this is allowed.
+ if is_rust_enum {
+ if !self.variants().is_empty() {
+ builder = builder.with_attr(attributes::repr(repr_name));
+ }
+ } else {
+ builder = builder.with_attr(attributes::repr("C"));
+ }
+
+ if let Some(comment) = item.comment() {
+ builder = builder.with_attr(attributes::doc(comment));
+ }
+
+ let derives = attributes::derives(&["Debug",
+ "Copy",
+ "Clone",
+ "PartialEq",
+ "Eq",
+ "Hash"]);
+
+ builder = builder.with_attr(derives);
+
+ fn add_constant<'a>(enum_: &Type,
+ // Only to avoid recomputing every time.
+ enum_canonical_name: &str,
+ // May be the same as "variant" if it's because the
+ // enum is unnamed and we still haven't seen the
+ // value.
+ variant_name: &str,
+ referenced_name: &str,
+ enum_rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult<'a>) {
+ let constant_name = if enum_.name().is_some() {
+ format!("{}_{}", enum_canonical_name, variant_name)
+ } else {
+ variant_name.into()
+ };
+
+ let constant = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .const_(constant_name)
+ .expr()
+ .path()
+ .ids(&[&*enum_canonical_name, referenced_name])
+ .build()
+ .build(enum_rust_ty);
+ result.push(constant);
+ }
+
+ let mut builder =
+ EnumBuilder::new(builder, &name, repr_name, is_rust_enum);
+
+ // A map where we keep a value -> variant relation.
+ let mut seen_values = HashMap::<_, String>::new();
+ let enum_rust_ty = item.to_rust_ty(ctx);
+ let is_toplevel = item.is_toplevel(ctx);
+
+ // Used to mangle the constants we generate in the unnamed-enum case.
+ let parent_canonical_name = if is_toplevel {
+ None
+ } else {
+ Some(item.parent_id().canonical_name(ctx))
+ };
+
+ let constant_mangling_prefix = if enum_ty.name().is_none() {
+ parent_canonical_name.as_ref().map(|n| &*n)
+ } else {
+ Some(&name)
+ };
+
+ // NB: We defer the creation of constified variants, in case we find
+ // another variant with the same value (which is the common thing to
+ // do).
+ let mut constified_variants = VecDeque::new();
+
+ let mut iter = self.variants().iter().peekable();
+ while let Some(variant) = iter.next().or_else(|| constified_variants.pop_front()) {
+ if variant.hidden() {
+ continue;
+ }
+
+ if variant.force_constification() && iter.peek().is_some() {
+ constified_variants.push_back(variant);
+ continue;
+ }
+
+ match seen_values.entry(variant.val()) {
+ Entry::Occupied(ref entry) => {
+ if is_rust_enum {
+ let variant_name = ctx.rust_mangle(variant.name());
+ let mangled_name = if is_toplevel ||
+ enum_ty.name().is_some() {
+ variant_name
+ } else {
+ let parent_name = parent_canonical_name.as_ref()
+ .unwrap();
+
+ Cow::Owned(
+ format!("{}_{}", parent_name, variant_name))
+ };
+
+ let existing_variant_name = entry.get();
+ add_constant(enum_ty,
+ &name,
+ &*mangled_name,
+ existing_variant_name,
+ enum_rust_ty.clone(),
+ result);
+ } else {
+ builder = builder.with_variant(ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result);
+ }
+ }
+ Entry::Vacant(entry) => {
+ builder = builder.with_variant(ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result);
+
+ let variant_name = ctx.rust_mangle(variant.name());
+
+ // If it's an unnamed enum, or constification is enforced,
+ // we also generate a constant so it can be properly
+ // accessed.
+ if (is_rust_enum && enum_ty.name().is_none()) ||
+ variant.force_constification() {
+ let mangled_name = if is_toplevel {
+ variant_name.clone()
+ } else {
+ let parent_name = parent_canonical_name.as_ref()
+ .unwrap();
+
+ Cow::Owned(
+ format!("{}_{}", parent_name, variant_name))
+ };
+
+ add_constant(enum_ty,
+ &name,
+ &mangled_name,
+ &variant_name,
+ enum_rust_ty.clone(),
+ result);
+ }
+
+ entry.insert(variant_name.into_owned());
+ }
+ }
+ }
+
+ let enum_ = builder.build(ctx, enum_rust_ty, result);
+ result.push(enum_);
+ }
+}
+
+trait ToRustTy {
+ type Extra;
+
+ fn to_rust_ty(&self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra)
+ -> P<ast::Ty>;
+}
+
+trait ItemToRustTy {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty>;
+}
+
+// Convenience implementation.
+impl ItemToRustTy for ItemId {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ ctx.resolve_item(*self).to_rust_ty(ctx)
+ }
+}
+
+impl ItemToRustTy for Item {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ self.kind().expect_type().to_rust_ty(ctx, self)
+ }
+}
+
+impl ToRustTy for Type {
+ type Extra = Item;
+
+ fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> {
+ use self::helpers::ast_ty::*;
+
+ match *self.kind() {
+ TypeKind::Void => raw_type(ctx, "c_void"),
+ // TODO: we should do something smart with nullptr, or maybe *const
+ // c_void is enough?
+ TypeKind::NullPtr => {
+ raw_type(ctx, "c_void").to_ptr(true, ctx.span())
+ }
+ TypeKind::Int(ik) => {
+ match ik {
+ IntKind::Bool => aster::ty::TyBuilder::new().bool(),
+ IntKind::Char => raw_type(ctx, "c_char"),
+ IntKind::UChar => raw_type(ctx, "c_uchar"),
+ IntKind::Short => raw_type(ctx, "c_short"),
+ IntKind::UShort => raw_type(ctx, "c_ushort"),
+ IntKind::Int => raw_type(ctx, "c_int"),
+ IntKind::UInt => raw_type(ctx, "c_uint"),
+ IntKind::Long => raw_type(ctx, "c_long"),
+ IntKind::ULong => raw_type(ctx, "c_ulong"),
+ IntKind::LongLong => raw_type(ctx, "c_longlong"),
+ IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
+
+ IntKind::I8 => aster::ty::TyBuilder::new().i8(),
+ IntKind::U8 => aster::ty::TyBuilder::new().u8(),
+ IntKind::I16 => aster::ty::TyBuilder::new().i16(),
+ IntKind::U16 => aster::ty::TyBuilder::new().u16(),
+ IntKind::I32 => aster::ty::TyBuilder::new().i32(),
+ IntKind::U32 => aster::ty::TyBuilder::new().u32(),
+ IntKind::I64 => aster::ty::TyBuilder::new().i64(),
+ IntKind::U64 => aster::ty::TyBuilder::new().u64(),
+ IntKind::Custom { name, .. } => {
+ let ident = ctx.rust_ident_raw(name);
+ quote_ty!(ctx.ext_cx(), $ident)
+ }
+ // FIXME: This doesn't generate the proper alignment, but we
+ // can't do better right now. We should be able to use
+ // i128/u128 when they're available.
+ IntKind::U128 | IntKind::I128 => {
+ aster::ty::TyBuilder::new().array(2).u64()
+ }
+ }
+ }
+ TypeKind::Float(fk) => float_kind_rust_type(ctx, fk),
+ TypeKind::Complex(fk) => {
+ let float_path = float_kind_rust_type(ctx, fk);
+
+ ctx.generated_bindegen_complex();
+ if ctx.options().enable_cxx_namespaces {
+ quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>)
+ } else {
+ quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>)
+ }
+ }
+ TypeKind::Function(ref fs) => {
+ let ty = fs.to_rust_ty(ctx, item);
+ let prefix = ctx.trait_prefix();
+ quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)
+ }
+ TypeKind::Array(item, len) => {
+ let inner = item.to_rust_ty(ctx);
+ aster::ty::TyBuilder::new().array(len).build(inner)
+ }
+ TypeKind::Enum(..) => {
+ let path = item.namespace_aware_canonical_path(ctx);
+ aster::AstBuilder::new().ty().path().ids(path).build()
+ }
+ TypeKind::TemplateRef(inner, ref template_args) => {
+ // PS: Sorry for the duplication here.
+ let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
+
+ if let ast::TyKind::Path(_, ref mut path) = inner_ty.node {
+ let template_args = template_args.iter()
+ .map(|arg| arg.to_rust_ty(ctx))
+ .collect::<Vec<_>>();
+
+ path.segments.last_mut().unwrap().parameters = if template_args.is_empty() {
+ None
+ } else {
+ Some(P(ast::PathParameters::AngleBracketed(
+ ast::AngleBracketedParameterData {
+ lifetimes: vec![],
+ types: P::from_vec(template_args),
+ bindings: P::from_vec(vec![]),
+ }
+ )))
+ }
+ }
+
+ P(inner_ty)
+ }
+ TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx),
+ TypeKind::TemplateAlias(ref spelling, inner, _) |
+ TypeKind::Alias(ref spelling, inner) => {
+ let applicable_named_args =
+ item.applicable_template_args(ctx)
+ .into_iter()
+ .filter(|arg| ctx.resolve_type(*arg).is_named())
+ .collect::<Vec<_>>();
+
+ if item.is_opaque(ctx) && !applicable_named_args.is_empty() {
+ // Pray if there's no available layout.
+ let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
+ BlobTyBuilder::new(layout).build()
+ } else if let Some(ty) = utils::type_from_named(ctx,
+ spelling,
+ inner) {
+ ty
+ } else {
+ utils::build_templated_path(item,
+ ctx,
+ applicable_named_args)
+ }
+ }
+ TypeKind::Comp(ref info) => {
+ let template_args = item.applicable_template_args(ctx);
+ if info.has_non_type_template_params() ||
+ (item.is_opaque(ctx) && !template_args.is_empty()) {
+ return match self.layout(ctx) {
+ Some(layout) => BlobTyBuilder::new(layout).build(),
+ None => {
+ warn!("Couldn't compute layout for a type with non \
+ type template params or opaque, expect \
+ dragons!");
+ aster::AstBuilder::new().ty().unit()
+ }
+ };
+ }
+
+ utils::build_templated_path(item, ctx, template_args)
+ }
+ TypeKind::BlockPointer => {
+ let void = raw_type(ctx, "c_void");
+ void.to_ptr(/* is_const = */
+ false,
+ ctx.span())
+ }
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) => {
+ let inner = ctx.resolve_item(inner);
+ let inner_ty = inner.expect_type();
+ let ty = inner.to_rust_ty(ctx);
+
+ // Avoid the first function pointer level, since it's already
+ // represented in Rust.
+ if inner_ty.canonical_type(ctx).is_function() {
+ ty
+ } else {
+ let is_const = self.is_const() ||
+ inner.expect_type().is_const();
+ ty.to_ptr(is_const, ctx.span())
+ }
+ }
+ TypeKind::Named(..) => {
+ let name = item.canonical_name(ctx);
+ let ident = ctx.rust_ident(&name);
+ quote_ty!(ctx.ext_cx(), $ident)
+ }
+ ref u @ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing {:?}!", u)
+ }
+ }
+ }
+}
+
+impl ToRustTy for FunctionSig {
+ type Extra = Item;
+
+ fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> {
+ // TODO: we might want to consider ignoring the reference return value.
+ let return_item = ctx.resolve_item(self.return_type());
+ let ret =
+ if let TypeKind::Void = *return_item.kind().expect_type().kind() {
+ ast::FunctionRetTy::Default(ctx.span())
+ } else {
+ ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
+ };
+
+ let mut unnamed_arguments = 0;
+ let arguments = self.argument_types().iter().map(|&(ref name, ty)| {
+ let arg_item = ctx.resolve_item(ty);
+ let arg_ty = arg_item.kind().expect_type();
+
+ // From the C90 standard[1]:
+ //
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ //
+ // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
+ let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
+ t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
+ } else {
+ arg_item.to_rust_ty(ctx)
+ };
+
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+
+ assert!(!arg_name.is_empty());
+
+ ast::Arg {
+ ty: arg_ty,
+ pat: aster::AstBuilder::new().pat().id(arg_name),
+ id: ast::DUMMY_NODE_ID,
+ }
+ }).collect::<Vec<_>>();
+
+ let decl = P(ast::FnDecl {
+ inputs: arguments,
+ output: ret,
+ variadic: self.is_variadic(),
+ });
+
+ let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: self.abi(),
+ lifetimes: vec![],
+ decl: decl,
+ }));
+
+ P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: fnty,
+ span: ctx.span(),
+ })
+ }
+}
+
+impl CodeGenerator for Function {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ _whitelisted_items: &ItemSet,
+ item: &Item) {
+ debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
+
+ let name = self.name();
+ let mut canonical_name = item.canonical_name(ctx);
+ let mangled_name = self.mangled_name();
+
+ {
+ let seen_symbol_name = mangled_name.unwrap_or(&canonical_name);
+
+ // TODO: Maybe warn here if there's a type/argument mismatch, or
+ // something?
+ if result.seen_function(seen_symbol_name) {
+ return;
+ }
+ result.saw_function(seen_symbol_name);
+ }
+
+ let signature_item = ctx.resolve_item(self.signature());
+ let signature = signature_item.kind().expect_type().canonical_type(ctx);
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("Signature kind is not a Function: {:?}", signature),
+ };
+
+ let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item);
+
+ let mut attributes = vec![];
+
+ if let Some(comment) = item.comment() {
+ attributes.push(attributes::doc(comment));
+ }
+
+ if let Some(mangled) = mangled_name {
+ attributes.push(attributes::link_name(mangled));
+ } else if name != canonical_name {
+ attributes.push(attributes::link_name(name));
+ }
+
+ let foreign_item_kind =
+ ast::ForeignItemKind::Fn(fndecl, ast::Generics::default());
+
+ // Handle overloaded functions by giving each overload its own unique
+ // suffix.
+ let times_seen = result.overload_number(&canonical_name);
+ if times_seen > 0 {
+ write!(&mut canonical_name, "{}", times_seen).unwrap();
+ }
+
+ let foreign_item = ast::ForeignItem {
+ ident: ctx.rust_ident_raw(&canonical_name),
+ attrs: attributes,
+ node: foreign_item_kind,
+ id: ast::DUMMY_NODE_ID,
+ span: ctx.span(),
+ vis: ast::Visibility::Public,
+ };
+
+ let item = ForeignModBuilder::new(signature.abi())
+ .with_foreign_item(foreign_item)
+ .build(ctx);
+
+ result.push(item);
+ }
+}
+
+pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
+ context.gen(|context| {
+ let counter = Cell::new(0);
+ let mut result = CodegenResult::new(&counter);
+
+ debug!("codegen: {:?}", context.options());
+
+ let whitelisted_items: ItemSet = context.whitelisted_items().collect();
+
+ if context.options().emit_ir {
+ for &id in whitelisted_items.iter() {
+ let item = context.resolve_item(id);
+ println!("ir: {:?} = {:#?}", id, item);
+ }
+ }
+
+ context.resolve_item(context.root_module())
+ .codegen(context, &mut result, &whitelisted_items, &());
+
+ result.items
+ })
+}
+
+mod utils {
+ use aster;
+ use ir::context::{BindgenContext, ItemId};
+ use ir::item::{Item, ItemCanonicalPath};
+ use ir::ty::TypeKind;
+ use std::mem;
+ use super::ItemToRustTy;
+ use syntax::ast;
+ use syntax::ptr::P;
+
+ pub fn prepend_union_types(ctx: &BindgenContext,
+ result: &mut Vec<P<ast::Item>>) {
+ let prefix = ctx.trait_prefix();
+
+ // TODO(emilio): The fmt::Debug impl could be way nicer with
+ // std::intrinsics::type_name, but...
+ let union_field_decl = quote_item!(ctx.ext_cx(),
+ #[repr(C)]
+ pub struct __BindgenUnionField<T>(
+ ::$prefix::marker::PhantomData<T>);
+ )
+ .unwrap();
+
+ let union_field_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub fn new() -> Self {
+ __BindgenUnionField(::$prefix::marker::PhantomData)
+ }
+
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ ::$prefix::mem::transmute(self)
+ }
+
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ ::$prefix::mem::transmute(self)
+ }
+ }
+ )
+ .unwrap();
+
+ let union_field_default_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::$prefix::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+ )
+ .unwrap();
+
+ let union_field_clone_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::$prefix::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+ }
+ )
+ .unwrap();
+
+ let union_field_copy_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::$prefix::marker::Copy for __BindgenUnionField<T> {}
+ )
+ .unwrap();
+
+ let union_field_debug_impl = quote_item!(ctx.ext_cx(),
+ impl<T> ::std::fmt::Debug for __BindgenUnionField<T> {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
+ -> ::std::fmt::Result {
+ fmt.write_str("__BindgenUnionField")
+ }
+ }
+ )
+ .unwrap();
+
+ let items = vec![
+ union_field_decl, union_field_impl,
+ union_field_default_impl,
+ union_field_clone_impl,
+ union_field_copy_impl,
+ union_field_debug_impl,
+ ];
+
+ let old_items = mem::replace(result, items);
+ result.extend(old_items.into_iter());
+ }
+
+ pub fn prepend_complex_type(ctx: &BindgenContext,
+ result: &mut Vec<P<ast::Item>>) {
+ let complex_type = quote_item!(ctx.ext_cx(),
+ #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)]
+ #[repr(C)]
+ pub struct __BindgenComplex<T> {
+ pub re: T,
+ pub im: T
+ }
+ )
+ .unwrap();
+
+ let items = vec![complex_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items.into_iter());
+ }
+
+ pub fn build_templated_path(item: &Item,
+ ctx: &BindgenContext,
+ template_args: Vec<ItemId>)
+ -> P<ast::Ty> {
+ let path = item.namespace_aware_canonical_path(ctx);
+ let builder = aster::AstBuilder::new().ty().path();
+
+ let template_args = template_args
+ .iter()
+ .map(|arg| arg.to_rust_ty(ctx))
+ .collect::<Vec<_>>();
+
+ // XXX: I suck at aster.
+ if path.len() == 1 {
+ return builder.segment(&path[0])
+ .with_tys(template_args)
+ .build()
+ .build();
+ }
+
+ let mut builder = builder.id(&path[0]);
+ for (i, segment) in path.iter().skip(1).enumerate() {
+ // Take into account the skip(1)
+ builder = if i == path.len() - 2 {
+ // XXX Extra clone courtesy of the borrow checker.
+ builder.segment(&segment)
+ .with_tys(template_args.clone())
+ .build()
+ } else {
+ builder.segment(&segment).build()
+ }
+ }
+
+ builder.build()
+ }
+
+ fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
+ let ident = ctx.rust_ident_raw(&name);
+ quote_ty!(ctx.ext_cx(), $ident)
+ }
+
+ pub fn type_from_named(ctx: &BindgenContext,
+ name: &str,
+ _inner: ItemId)
+ -> Option<P<ast::Ty>> {
+ // FIXME: We could use the inner item to check this is really a
+ // primitive type but, who the heck overrides these anyway?
+ Some(match name {
+ "int8_t" => primitive_ty(ctx, "i8"),
+ "uint8_t" => primitive_ty(ctx, "u8"),
+ "int16_t" => primitive_ty(ctx, "i16"),
+ "uint16_t" => primitive_ty(ctx, "u16"),
+ "int32_t" => primitive_ty(ctx, "i32"),
+ "uint32_t" => primitive_ty(ctx, "u32"),
+ "int64_t" => primitive_ty(ctx, "i64"),
+ "uint64_t" => primitive_ty(ctx, "u64"),
+
+ "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"),
+
+ "intptr_t" | "ptrdiff_t" | "ssize_t" => primitive_ty(ctx, "isize"),
+ _ => return None,
+ })
+ }
+
+ pub fn rust_fndecl_from_signature(ctx: &BindgenContext,
+ sig: &Item)
+ -> P<ast::FnDecl> {
+ use codegen::ToRustTy;
+
+ let signature = sig.kind().expect_type().canonical_type(ctx);
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How?"),
+ };
+
+ let decl_ty = signature.to_rust_ty(ctx, sig);
+ match decl_ty.unwrap().node {
+ ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl,
+ _ => panic!("How did this happen exactly?"),
+ }
+ }
+}
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
new file mode 100644
index 00000000..98be0540
--- /dev/null
+++ b/src/ir/annotations.rs
@@ -0,0 +1,188 @@
+//! Types and functions related to bindgen annotation comments.
+//!
+//! Users can add annotations in doc comments to types that they would like to
+//! replace other types with, mark as opaque, etc. This module deals with all of
+//! that stuff.
+
+use clang;
+
+/// What kind of accessor should we provide for a field?
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum FieldAccessorKind {
+ /// No accessor.
+ None,
+ /// Plain accessor.
+ Regular,
+ /// Unsafe accessor.
+ Unsafe,
+ /// Immutable accessor.
+ Immutable,
+}
+
+/// Annotations for a given item, or a field.
+///
+/// You can see the kind of comments that are accepted in the Doxygen
+/// documentation:
+///
+/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
+#[derive(Clone, PartialEq, Debug)]
+pub struct Annotations {
+ /// Whether this item is marked as opaque. Only applies to types.
+ opaque: bool,
+ /// Whether this item should be hidden from the output. Only applies to
+ /// types, or enum variants.
+ hide: bool,
+ /// Whether this type should be replaced by another. The name is a
+ /// namespace-aware path.
+ use_instead_of: Option<Vec<String>>,
+ /// Manually disable deriving copy/clone on this type. Only applies to
+ /// struct or union types.
+ disallow_copy: bool,
+ /// Whether fields should be marked as private or not. You can set this on
+ /// structs (it will apply to all the fields), or individual fields.
+ private_fields: Option<bool>,
+ /// The kind of accessor this field will have. Also can be applied to
+ /// structs so all the fields inside share it by default.
+ accessor_kind: Option<FieldAccessorKind>,
+ /// Whether this enum variant should be constified.
+ ///
+ /// This is controlled by the `constant` attribute, this way:
+ ///
+ /// ```cpp
+ /// enum Foo {
+ /// Bar = 0, /**< <div rustbindgen constant></div> */
+ /// Baz = 0,
+ /// };
+ /// ```
+ ///
+ /// In that case, bindgen will generate a constant for `Bar` instead of
+ /// `Baz`.
+ constify_enum_variant: bool,
+}
+
+fn parse_accessor(s: &str) -> FieldAccessorKind {
+ match s {
+ "false" => FieldAccessorKind::None,
+ "unsafe" => FieldAccessorKind::Unsafe,
+ "immutable" => FieldAccessorKind::Immutable,
+ _ => FieldAccessorKind::Regular,
+ }
+}
+
+impl Default for Annotations {
+ fn default() -> Self {
+ Annotations {
+ opaque: false,
+ hide: false,
+ use_instead_of: None,
+ disallow_copy: false,
+ private_fields: None,
+ accessor_kind: None,
+ constify_enum_variant: false,
+ }
+ }
+}
+
+impl Annotations {
+ /// Construct new annotations for the given cursor and its bindgen comments
+ /// (if any).
+ pub fn new(cursor: &clang::Cursor) -> Option<Annotations> {
+ let mut anno = Annotations::default();
+ let mut matched_one = false;
+ anno.parse(&cursor.comment(), &mut matched_one);
+
+ if matched_one { Some(anno) } else { None }
+ }
+
+ /// Should this type be hidden?
+ pub fn hide(&self) -> bool {
+ self.hide
+ }
+
+ /// Should this type be opaque?
+ pub fn opaque(&self) -> bool {
+ self.opaque
+ }
+
+ /// For a given type, indicates the type it should replace.
+ ///
+ /// For example, in the following code:
+ ///
+ /// ```cpp
+ ///
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Foo { int x; };
+ ///
+ /// struct Bar { char foo; };
+ /// ```
+ ///
+ /// the generated code would look something like:
+ ///
+ /// ```
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Bar {
+ /// x: ::std::os::raw::c_int,
+ /// };
+ /// ```
+ ///
+ /// That is, code for `Foo` is used to generate `Bar`.
+ pub fn use_instead_of(&self) -> Option<&[String]> {
+ self.use_instead_of.as_ref().map(|s| &**s)
+ }
+
+ /// Should we avoid implementing the `Copy` trait?
+ pub fn disallow_copy(&self) -> bool {
+ self.disallow_copy
+ }
+
+ /// Should the fields be private?
+ pub fn private_fields(&self) -> Option<bool> {
+ self.private_fields
+ }
+
+ /// What kind of accessors should we provide for this type's fields?
+ pub fn accessor_kind(&self) -> Option<FieldAccessorKind> {
+ self.accessor_kind
+ }
+
+ fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
+ use clang_sys::CXComment_HTMLStartTag;
+ if comment.kind() == CXComment_HTMLStartTag &&
+ comment.get_tag_name() == "div" &&
+ comment.get_tag_attrs()
+ .next()
+ .map_or(false, |attr| attr.name == "rustbindgen") {
+ *matched = true;
+ for attr in comment.get_tag_attrs() {
+ match attr.name.as_str() {
+ "opaque" => self.opaque = true,
+ "hide" => self.hide = true,
+ "nocopy" => self.disallow_copy = true,
+ "replaces" => {
+ self.use_instead_of = Some(attr.value
+ .split("::")
+ .map(Into::into)
+ .collect())
+ }
+ "private" => {
+ self.private_fields = Some(attr.value != "false")
+ }
+ "accessor" => {
+ self.accessor_kind = Some(parse_accessor(&attr.value))
+ }
+ "constant" => self.constify_enum_variant = true,
+ _ => {}
+ }
+ }
+ }
+
+ for child in comment.get_children() {
+ self.parse(&child, matched);
+ }
+ }
+
+ /// Returns whether we've parsed a "constant" attribute.
+ pub fn constify_enum_variant(&self) -> bool {
+ self.constify_enum_variant
+ }
+}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
new file mode 100644
index 00000000..968bf879
--- /dev/null
+++ b/src/ir/comp.rs
@@ -0,0 +1,962 @@
+//! Compound types (unions and structs) in our intermediate representation.
+
+use clang;
+use parse::{ClangItemParser, ParseError};
+use std::cell::Cell;
+use super::annotations::Annotations;
+use super::context::{BindgenContext, ItemId};
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::item::Item;
+use super::layout::Layout;
+use super::ty::Type;
+use super::type_collector::{ItemSet, TypeCollector};
+
+/// The kind of compound type.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum CompKind {
+ /// A struct.
+ Struct,
+ /// A union.
+ Union,
+}
+
+/// The kind of C++ method.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum MethodKind {
+ /// A constructor. We represent it as method for convenience, to avoid code
+ /// duplication.
+ Constructor,
+ /// A static method.
+ Static,
+ /// A normal method.
+ Normal,
+ /// A virtual method.
+ Virtual,
+}
+
+/// A struct representing a C++ method, either static, normal, or virtual.
+#[derive(Debug)]
+pub struct Method {
+ kind: MethodKind,
+ /// The signature of the method. Take into account this is not a `Type`
+ /// item, but a `Function` one.
+ ///
+ /// This is tricky and probably this field should be renamed.
+ signature: ItemId,
+ is_const: bool,
+}
+
+impl Method {
+ /// Construct a new `Method`.
+ pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ Method {
+ kind: kind,
+ signature: signature,
+ is_const: is_const,
+ }
+ }
+
+ /// What kind of method is this?
+ pub fn kind(&self) -> MethodKind {
+ self.kind
+ }
+
+ /// Is this a constructor?
+ pub fn is_constructor(&self) -> bool {
+ self.kind == MethodKind::Constructor
+ }
+
+ /// Is this a virtual method?
+ pub fn is_virtual(&self) -> bool {
+ self.kind == MethodKind::Virtual
+ }
+
+ /// Is this a static method?
+ pub fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ /// Get the `ItemId` for the `Function` signature for this method.
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+
+ /// Is this a const qualified method?
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+}
+
+/// A struct representing a C++ field.
+#[derive(Clone, Debug)]
+pub struct Field {
+ /// The name of the field, empty if it's an unnamed bitfield width.
+ name: Option<String>,
+ /// The inner type.
+ ty: ItemId,
+ /// The doc comment on the field if any.
+ comment: Option<String>,
+ /// Annotations for this field, or the default.
+ annotations: Annotations,
+ /// If this field is a bitfield, and how many bits does it contain if it is.
+ bitfield: Option<u32>,
+ /// If the C++ field is marked as `mutable`
+ mutable: bool,
+}
+
+impl Field {
+ /// Construct a new `Field`.
+ pub fn new(name: Option<String>,
+ ty: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ bitfield: Option<u32>,
+ mutable: bool)
+ -> Field {
+ Field {
+ name: name,
+ ty: ty,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ bitfield: bitfield,
+ mutable: mutable,
+ }
+ }
+
+ /// Get the name of this field.
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ /// Get the type of this field.
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ /// Get the comment for this field.
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ /// If this is a bitfield, how many bits does it need?
+ pub fn bitfield(&self) -> Option<u32> {
+ self.bitfield
+ }
+
+ /// Is this field marked as `mutable`?
+ pub fn is_mutable(&self) -> bool {
+ self.mutable
+ }
+
+ /// Get the annotations for this field.
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+}
+
+impl CanDeriveDebug for Field {
+ type Extra = ();
+
+ fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_debug(ctx, ())
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for Field {
+ type Extra = ();
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_copy(ctx, ())
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.ty.can_derive_copy_in_array(ctx, ())
+ }
+}
+
+
+/// The kind of inheritance a base class is using.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum BaseKind {
+ /// Normal inheritance, like:
+ ///
+ /// ```cpp
+ /// class A : public B {};
+ /// ```
+ Normal,
+ /// Virtual inheritance, like:
+ ///
+ /// ```cpp
+ /// class A: public virtual B {};
+ /// ```
+ Virtual,
+}
+
+/// A base class.
+#[derive(Clone, Debug)]
+pub struct Base {
+ /// The type of this base class.
+ pub ty: ItemId,
+ /// The kind of inheritance we're doing.
+ pub kind: BaseKind,
+}
+
+impl Base {
+ /// Whether this base class is inheriting virtually.
+ pub fn is_virtual(&self) -> bool {
+ self.kind == BaseKind::Virtual
+ }
+}
+
+/// A compound type.
+///
+/// Either a struct or union, a compound type is built up from the combination
+/// of fields which also are associated with their own (potentially compound)
+/// type.
+#[derive(Debug)]
+pub struct CompInfo {
+ /// Whether this is a struct or a union.
+ kind: CompKind,
+
+ /// The members of this struct or union.
+ fields: Vec<Field>,
+
+ /// The template parameters of this class. These are non-concrete, and
+ /// should always be a Type(TypeKind::Named(name)), but still they need to
+ /// be registered with an unique type id in the context.
+ template_args: Vec<ItemId>,
+
+ /// The method declarations inside this class, if in C++ mode.
+ methods: Vec<Method>,
+
+ /// The different constructors this struct or class contains.
+ constructors: Vec<ItemId>,
+
+ /// Vector of classes this one inherits from.
+ base_members: Vec<Base>,
+
+ /// The parent reference template if any.
+ ref_template: Option<ItemId>,
+
+ /// The inner types that were declared inside this class, in something like:
+ ///
+ /// class Foo {
+ /// typedef int FooTy;
+ /// struct Bar {
+ /// int baz;
+ /// };
+ /// }
+ ///
+ /// static Foo::Bar const = {3};
+ inner_types: Vec<ItemId>,
+
+ /// Set of static constants declared inside this class.
+ inner_vars: Vec<ItemId>,
+
+ /// Whether this type should generate an vtable (TODO: Should be able to
+ /// look at the virtual methods and ditch this field).
+ has_vtable: bool,
+
+ /// Whether this type has destructor.
+ has_destructor: bool,
+
+ /// Whether this type has a base type with more than one member.
+ ///
+ /// TODO: We should be able to compute this.
+ has_nonempty_base: bool,
+
+ /// If this type has a template parameter which is not a type (e.g.: a
+ /// size_t)
+ has_non_type_template_params: bool,
+
+ /// Whether this struct layout is packed.
+ packed: bool,
+
+ /// Whether this struct is anonymous.
+ is_anonymous: bool,
+
+ /// Used to know if we've found an opaque attribute that could cause us to
+ /// generate a type with invalid layout. This is explicitly used to avoid us
+ /// generating bad alignments when parsing types like max_align_t.
+ ///
+ /// It's not clear what the behavior should be here, if generating the item
+ /// and pray, or behave as an opaque type.
+ found_unknown_attr: bool,
+
+ /// Used to detect if we've run in a can_derive_debug cycle while cycling
+ /// around the template arguments.
+ detect_derive_debug_cycle: Cell<bool>,
+
+ /// Used to detect if we've run in a has_destructor cycle while cycling
+ /// around the template arguments.
+ detect_has_destructor_cycle: Cell<bool>,
+}
+
+impl CompInfo {
+ /// Construct a new compound type.
+ pub fn new(kind: CompKind) -> Self {
+ CompInfo {
+ kind: kind,
+ fields: vec![],
+ template_args: vec![],
+ methods: vec![],
+ constructors: vec![],
+ base_members: vec![],
+ ref_template: None,
+ inner_types: vec![],
+ inner_vars: vec![],
+ has_vtable: false,
+ has_destructor: false,
+ has_nonempty_base: false,
+ has_non_type_template_params: false,
+ packed: false,
+ is_anonymous: false,
+ found_unknown_attr: false,
+ detect_derive_debug_cycle: Cell::new(false),
+ detect_has_destructor_cycle: Cell::new(false),
+ }
+ }
+
+ /// Is this compound type unsized?
+ pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
+ !self.has_vtable(ctx) && self.fields.is_empty() &&
+ self.base_members.iter().all(|base| {
+ ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
+ }) &&
+ self.ref_template
+ .map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
+ }
+
+ /// Does this compound type have a destructor?
+ pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
+ if self.detect_has_destructor_cycle.get() {
+ warn!("Cycle detected looking for destructors");
+ // Assume no destructor, since we don't have an explicit one.
+ return false;
+ }
+
+ self.detect_has_destructor_cycle.set(true);
+
+ let has_destructor = self.has_destructor ||
+ match self.kind {
+ CompKind::Union => false,
+ CompKind::Struct => {
+ // NB: We can't rely on a type with type parameters
+ // not having destructor.
+ //
+ // This is unfortunate, but...
+ self.ref_template.as_ref().map_or(false, |t| {
+ ctx.resolve_type(*t).has_destructor(ctx)
+ }) ||
+ self.template_args.iter().any(|t| {
+ ctx.resolve_type(*t).has_destructor(ctx)
+ }) ||
+ self.base_members.iter().any(|base| {
+ ctx.resolve_type(base.ty).has_destructor(ctx)
+ }) ||
+ self.fields.iter().any(|field| {
+ ctx.resolve_type(field.ty)
+ .has_destructor(ctx)
+ })
+ }
+ };
+
+ self.detect_has_destructor_cycle.set(false);
+
+ has_destructor
+ }
+
+ /// Is this type a template specialization?
+ pub fn is_template_specialization(&self) -> bool {
+ self.ref_template.is_some()
+ }
+
+ /// Get the template declaration this specialization is specializing.
+ pub fn specialized_template(&self) -> Option<ItemId> {
+ self.ref_template
+ }
+
+ /// Compute the layout of this type.
+ ///
+ /// This is called as a fallback under some circumstances where LLVM doesn't
+ /// give us the correct layout.
+ ///
+ /// If we're a union without known layout, we try to compute it from our
+ /// members. This is not ideal, but clang fails to report the size for these
+ /// kind of unions, see test/headers/template_union.hpp
+ pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ use std::cmp;
+
+ // We can't do better than clang here, sorry.
+ if self.kind == CompKind::Struct {
+ return None;
+ }
+
+ let mut max_size = 0;
+ let mut max_align = 0;
+ for field in &self.fields {
+ let field_layout = ctx.resolve_type(field.ty)
+ .layout(ctx);
+
+ if let Some(layout) = field_layout {
+ max_size = cmp::max(max_size, layout.size);
+ max_align = cmp::max(max_align, layout.align);
+ }
+ }
+
+ Some(Layout::new(max_size, max_align))
+ }
+
+ /// Get this type's set of fields.
+ pub fn fields(&self) -> &[Field] {
+ &self.fields
+ }
+
+ /// Get this type's set of free template arguments. Empty if this is not a
+ /// template.
+ pub fn template_args(&self) -> &[ItemId] {
+ &self.template_args
+ }
+
+ /// Does this type have any template parameters that aren't types
+ /// (e.g. int)?
+ pub fn has_non_type_template_params(&self) -> bool {
+ self.has_non_type_template_params
+ }
+
+ /// Does this type have a virtual table?
+ pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.has_vtable ||
+ self.base_members().iter().any(|base| {
+ ctx.resolve_type(base.ty)
+ .has_vtable(ctx)
+ }) ||
+ self.ref_template.map_or(false, |template| {
+ ctx.resolve_type(template).has_vtable(ctx)
+ })
+ }
+
+ /// Get this type's set of methods.
+ pub fn methods(&self) -> &[Method] {
+ &self.methods
+ }
+
+ /// Get this type's set of constructors.
+ pub fn constructors(&self) -> &[ItemId] {
+ &self.constructors
+ }
+
+ /// What kind of compound type is this?
+ pub fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ /// The set of types that this one inherits from.
+ pub fn base_members(&self) -> &[Base] {
+ &self.base_members
+ }
+
+ /// Construct a new compound type from a Clang type.
+ pub fn from_ty(potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ ctx: &mut BindgenContext)
+ -> Result<Self, ParseError> {
+ use clang_sys::*;
+ // Sigh... For class templates we want the location, for
+ // specialisations, we want the declaration... So just try both.
+ //
+ // TODO: Yeah, this code reads really bad.
+ let mut cursor = ty.declaration();
+ let mut kind = Self::kind_from_cursor(&cursor);
+ if kind.is_err() {
+ if let Some(location) = location {
+ kind = Self::kind_from_cursor(&location);
+ cursor = location;
+ }
+ }
+
+ let kind = try!(kind);
+
+ debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
+
+ let mut ci = CompInfo::new(kind);
+ ci.is_anonymous = cursor.is_anonymous();
+ ci.template_args = match ty.template_args() {
+ // In forward declarations and not specializations,
+ // etc, they are in
+ // the ast, we'll meet them in
+ // CXCursor_TemplateTypeParameter
+ None => vec![],
+ Some(arg_types) => {
+ let num_arg_types = arg_types.len();
+ let mut specialization = true;
+
+ let args = arg_types.filter(|t| t.kind() != CXType_Invalid)
+ .filter_map(|t| {
+ if t.spelling().starts_with("type-parameter") {
+ specialization = false;
+ None
+ } else {
+ Some(Item::from_ty_or_ref(t, None, None, ctx))
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if specialization && args.len() != num_arg_types {
+ ci.has_non_type_template_params = true;
+ warn!("warning: Template parameter is not a type");
+ }
+
+ if specialization { args } else { vec![] }
+ }
+ };
+
+ ci.ref_template = cursor.specialized()
+ .and_then(|c| Item::parse(c, None, ctx).ok());
+
+ let mut maybe_anonymous_struct_field = None;
+ cursor.visit(|cur| {
+ if cur.kind() != CXCursor_FieldDecl {
+ if let Some((ty, _)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+ maybe_anonymous_struct_field = None;
+ }
+
+ match cur.kind() {
+ CXCursor_FieldDecl => {
+ match maybe_anonymous_struct_field.take() {
+ Some((ty, clang_ty)) => {
+ let mut used = false;
+ cur.visit(|child| {
+ if child.cur_type() == clang_ty {
+ used = true;
+ }
+ CXChildVisit_Continue
+ });
+ if !used {
+ let field = Field::new(None,
+ ty,
+ None,
+ None,
+ None,
+ false);
+ ci.fields.push(field);
+ }
+ }
+ None => {}
+ }
+
+ let bit_width = cur.bit_width();
+ let field_type = Item::from_ty_or_ref(cur.cur_type(),
+ Some(cur),
+ Some(potential_id),
+ ctx);
+
+ let comment = cur.raw_comment();
+ let annotations = Annotations::new(&cur);
+ let name = cur.spelling();
+ let is_mutable = cursor.is_mutable_field();
+
+ // Name can be empty if there are bitfields, for example,
+ // see tests/headers/struct_with_bitfields.h
+ assert!(!name.is_empty() || bit_width.is_some(),
+ "Empty field name?");
+
+ let name = if name.is_empty() { None } else { Some(name) };
+
+ let field = Field::new(name,
+ field_type,
+ comment,
+ annotations,
+ bit_width,
+ is_mutable);
+ ci.fields.push(field);
+
+ // No we look for things like attributes and stuff.
+ cur.visit(|cur| {
+ if cur.kind() == CXCursor_UnexposedAttr {
+ ci.found_unknown_attr = true;
+ }
+ CXChildVisit_Continue
+ });
+
+ }
+ CXCursor_UnexposedAttr => {
+ ci.found_unknown_attr = true;
+ }
+ CXCursor_EnumDecl |
+ CXCursor_TypeAliasDecl |
+ CXCursor_TypedefDecl |
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ let inner = Item::parse(cur, Some(potential_id), ctx)
+ .expect("Inner ClassDecl");
+ if !ci.inner_types.contains(&inner) {
+ ci.inner_types.push(inner);
+ }
+ // A declaration of an union or a struct without name could
+ // also be an unnamed field, unfortunately.
+ if cur.spelling().is_empty() &&
+ cur.kind() != CXCursor_EnumDecl {
+ let ty = cur.cur_type();
+ maybe_anonymous_struct_field = Some((inner, ty));
+ }
+ }
+ CXCursor_PackedAttr => {
+ ci.packed = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ // Yes! You can arrive here with an empty template parameter
+ // name! Awesome, isn't it?
+ //
+ // see tests/headers/empty_template_param_name.hpp
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let param =
+ Item::named_type(cur.spelling(), potential_id, ctx);
+ ci.template_args.push(param);
+ }
+ CXCursor_CXXBaseSpecifier => {
+ let is_virtual_base = cur.is_virtual_base();
+ ci.has_vtable |= is_virtual_base;
+
+ let kind = if is_virtual_base {
+ BaseKind::Virtual
+ } else {
+ BaseKind::Normal
+ };
+
+ let type_id = Item::from_ty_or_ref(cur.cur_type(),
+ Some(cur),
+ None,
+ ctx);
+ ci.base_members.push(Base {
+ ty: type_id,
+ kind: kind,
+ });
+ }
+ CXCursor_Constructor |
+ CXCursor_Destructor |
+ CXCursor_CXXMethod => {
+ let is_virtual = cur.method_is_virtual();
+ let is_static = cur.method_is_static();
+ debug_assert!(!(is_static && is_virtual), "How?");
+
+ ci.has_destructor |= cur.kind() == CXCursor_Destructor;
+ ci.has_vtable |= is_virtual;
+
+ // This used to not be here, but then I tried generating
+ // stylo bindings with this (without path filters), and
+ // cried a lot with a method in gfx/Point.h
+ // (ToUnknownPoint), that somehow was causing the same type
+ // to be inserted in the map two times.
+ //
+ // I couldn't make a reduced test case, but anyway...
+ // Methods of template functions not only use to be inlined,
+ // but also instantiated, and we wouldn't be able to call
+ // them, so just bail out.
+ if !ci.template_args.is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ // NB: This gets us an owned `Function`, not a
+ // `FunctionSig`.
+ let signature = match Item::parse(cur, Some(potential_id), ctx) {
+ Ok(item) if ctx.resolve_item(item).kind().is_function() => item,
+ _ => return CXChildVisit_Continue,
+ };
+
+ match cur.kind() {
+ CXCursor_Constructor => {
+ ci.constructors.push(signature);
+ }
+ // TODO(emilio): Bind the destructor?
+ CXCursor_Destructor => {}
+ CXCursor_CXXMethod => {
+ let is_const = cur.method_is_const();
+ let method_kind = if is_static {
+ MethodKind::Static
+ } else if is_virtual {
+ MethodKind::Virtual
+ } else {
+ MethodKind::Normal
+ };
+
+ let method =
+ Method::new(method_kind, signature, is_const);
+
+ ci.methods.push(method);
+ }
+ _ => unreachable!("How can we see this here?"),
+ }
+ }
+ CXCursor_NonTypeTemplateParameter => {
+ ci.has_non_type_template_params = true;
+ }
+ CXCursor_VarDecl => {
+ let linkage = cur.linkage();
+ if linkage != CXLinkage_External &&
+ linkage != CXLinkage_UniqueExternal {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cur.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if let Ok(item) = Item::parse(cur,
+ Some(potential_id),
+ ctx) {
+ ci.inner_vars.push(item);
+ }
+ }
+ // Intentionally not handled
+ CXCursor_CXXAccessSpecifier |
+ CXCursor_CXXFinalAttr |
+ CXCursor_FunctionTemplate |
+ CXCursor_ConversionFunction => {}
+ _ => {
+ warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
+ cur.spelling(),
+ cur.kind(),
+ cursor.spelling(),
+ cur.location());
+ }
+ }
+ CXChildVisit_Continue
+ });
+
+ if let Some((ty, _)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+
+ Ok(ci)
+ }
+
+ fn kind_from_cursor(cursor: &clang::Cursor)
+ -> Result<CompKind, ParseError> {
+ use clang_sys::*;
+ Ok(match cursor.kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ CXCursor_ClassDecl |
+ CXCursor_StructDecl => CompKind::Struct,
+ CXCursor_CXXBaseSpecifier |
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_ClassTemplate => {
+ match cursor.template_kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ _ => CompKind::Struct,
+ }
+ }
+ _ => {
+ warn!("Unknown kind for comp type: {:?}", cursor);
+ return Err(ParseError::Continue);
+ }
+ })
+ }
+
+ /// Do any of the types that participate in this type's "signature" use the
+ /// named type `ty`?
+ ///
+ /// See also documentation for `ir::Item::signature_contains_named_type`.
+ pub fn signature_contains_named_type(&self,
+ ctx: &BindgenContext,
+ ty: &Type)
+ -> bool {
+ // We don't generate these, so rather don't make the codegen step to
+ // think we got it covered.
+ if self.has_non_type_template_params() {
+ return false;
+ }
+ self.template_args.iter().any(|arg| {
+ ctx.resolve_type(*arg)
+ .signature_contains_named_type(ctx, ty)
+ })
+ }
+
+ /// Get the set of types that were declared within this compound type
+ /// (e.g. nested class definitions).
+ pub fn inner_types(&self) -> &[ItemId] {
+ &self.inner_types
+ }
+
+ /// Get the set of static variables declared within this compound type.
+ pub fn inner_vars(&self) -> &[ItemId] {
+ &self.inner_vars
+ }
+
+ /// Have we found a field with an opaque type that could potentially mess up
+ /// the layout of this compound type?
+ pub fn found_unknown_attr(&self) -> bool {
+ self.found_unknown_attr
+ }
+
+ /// Is this compound type packed?
+ pub fn packed(&self) -> bool {
+ self.packed
+ }
+
+ /// Returns whether this type needs an explicit vtable because it has
+ /// virtual methods and none of its base classes has already a vtable.
+ pub fn needs_explicit_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.has_vtable(ctx) &&
+ !self.base_members.iter().any(|base| {
+ // NB: Ideally, we could rely in all these types being `comp`, and
+ // life would be beautiful.
+ //
+ // Unfortunately, given the way we implement --match-pat, and also
+ // that you can inherit from templated types, we need to handle
+ // other cases here too.
+ ctx.resolve_type(base.ty)
+ .canonical_type(ctx)
+ .as_comp()
+ .map_or(false, |ci| ci.has_vtable(ctx))
+ })
+ }
+}
+
+impl CanDeriveDebug for CompInfo {
+ type Extra = Option<Layout>;
+
+ fn can_derive_debug(&self,
+ ctx: &BindgenContext,
+ layout: Option<Layout>)
+ -> bool {
+ if self.has_non_type_template_params() {
+ return layout.map_or(false, |l| l.opaque().can_derive_debug(ctx, ()));
+ }
+
+ // We can reach here recursively via template parameters of a member,
+ // for example.
+ if self.detect_derive_debug_cycle.get() {
+ warn!("Derive debug cycle detected!");
+ return true;
+ }
+
+ if self.kind == CompKind::Union {
+ if ctx.options().unstable_rust {
+ return false;
+ }
+
+ return layout.unwrap_or_else(Layout::zero)
+ .opaque()
+ .can_derive_debug(ctx, ());
+ }
+
+ self.detect_derive_debug_cycle.set(true);
+
+ let can_derive_debug = {
+ self.base_members
+ .iter()
+ .all(|base| base.ty.can_derive_debug(ctx, ())) &&
+ self.template_args
+ .iter()
+ .all(|id| id.can_derive_debug(ctx, ())) &&
+ self.fields
+ .iter()
+ .all(|f| f.can_derive_debug(ctx, ())) &&
+ self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
+ };
+
+ self.detect_derive_debug_cycle.set(false);
+
+ can_derive_debug
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for CompInfo {
+ type Extra = (&'a Item, Option<Layout>);
+
+ fn can_derive_copy(&self,
+ ctx: &BindgenContext,
+ (item, layout): (&Item, Option<Layout>))
+ -> bool {
+ if self.has_non_type_template_params() {
+ return layout.map_or(false, |l| l.opaque().can_derive_copy(ctx, ()));
+ }
+
+ // NOTE: Take into account that while unions in C and C++ are copied by
+ // default, the may have an explicit destructor in C++, so we can't
+ // defer this check just for the union case.
+ if self.has_destructor(ctx) {
+ return false;
+ }
+
+ if self.kind == CompKind::Union {
+ if !ctx.options().unstable_rust {
+ // NOTE: If there's no template parameters we can derive copy
+ // unconditionally, since arrays are magical for rustc, and
+ // __BindgenUnionField always implements copy.
+ return true;
+ }
+
+ // https://github.com/rust-lang/rust/issues/36640
+ if !self.template_args.is_empty() || self.ref_template.is_some() ||
+ !item.applicable_template_args(ctx).is_empty() {
+ return false;
+ }
+ }
+
+ // With template args, use a safe subset of the types,
+ // since copyability depends on the types itself.
+ self.ref_template
+ .as_ref()
+ .map_or(true, |t| t.can_derive_copy(ctx, ())) &&
+ self.base_members
+ .iter()
+ .all(|base| base.ty.can_derive_copy(ctx, ())) &&
+ self.fields.iter().all(|field| field.can_derive_copy(ctx, ()))
+ }
+
+ fn can_derive_copy_in_array(&self,
+ ctx: &BindgenContext,
+ extra: (&Item, Option<Layout>))
+ -> bool {
+ self.can_derive_copy(ctx, extra)
+ }
+}
+
+impl TypeCollector for CompInfo {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ if let Some(template) = self.specialized_template() {
+ types.insert(template);
+ }
+
+ let applicable_template_args = item.applicable_template_args(context);
+ for arg in applicable_template_args {
+ types.insert(arg);
+ }
+
+ for base in self.base_members() {
+ types.insert(base.ty);
+ }
+
+ for field in self.fields() {
+ types.insert(field.ty());
+ }
+
+ for &ty in self.inner_types() {
+ types.insert(ty);
+ }
+
+ for &var in self.inner_vars() {
+ types.insert(var);
+ }
+
+ // FIXME(emilio): Methods, VTable?
+ }
+}
diff --git a/src/ir/context.rs b/src/ir/context.rs
new file mode 100644
index 00000000..b0143bd5
--- /dev/null
+++ b/src/ir/context.rs
@@ -0,0 +1,1267 @@
+//! Common context that is passed around during parsing and codegen.
+
+use BindgenOptions;
+use cexpr;
+use chooser::TypeChooser;
+use clang::{self, Cursor};
+use parse::ClangItemParser;
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::collections::{HashMap, VecDeque, hash_map};
+use std::collections::btree_map::{self, BTreeMap};
+use std::fmt;
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::int::IntKind;
+use super::item::{Item, ItemCanonicalPath};
+use super::item_kind::ItemKind;
+use super::module::{Module, ModuleKind};
+use super::ty::{FloatKind, Type, TypeKind};
+use super::type_collector::{ItemSet, TypeCollector};
+use syntax::ast::Ident;
+use syntax::codemap::{DUMMY_SP, Span};
+use syntax::ext::base::ExtCtxt;
+
+/// A single identifier for an item.
+///
+/// TODO: Build stronger abstractions on top of this, like TypeId(ItemId)?
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct ItemId(usize);
+
+impl ItemId {
+ /// Get a numeric representation of this id.
+ pub fn as_usize(&self) -> usize {
+ self.0
+ }
+}
+
+impl CanDeriveDebug for ItemId {
+ type Extra = ();
+
+ fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
+ ctx.resolve_item(*self).can_derive_debug(ctx, ())
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for ItemId {
+ type Extra = ();
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
+ ctx.resolve_item(*self).can_derive_copy(ctx, ())
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ ctx.resolve_item(*self).can_derive_copy_in_array(ctx, ())
+ }
+}
+
+/// A key used to index a resolved type, so we only process it once.
+///
+/// This is almost always a USR string (an unique identifier generated by
+/// clang), but it can also be the canonical declaration if the type is unnamed,
+/// in which case clang may generate the same USR for multiple nested unnamed
+/// types.
+#[derive(Eq, PartialEq, Hash, Debug)]
+enum TypeKey {
+ USR(String),
+ Declaration(Cursor),
+}
+
+// This is just convenience to avoid creating a manual debug impl for the
+// context.
+struct GenContext<'ctx>(ExtCtxt<'ctx>);
+
+impl<'ctx> fmt::Debug for GenContext<'ctx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "GenContext {{ ... }}")
+ }
+}
+
+/// A context used during parsing and generation of structs.
+#[derive(Debug)]
+pub struct BindgenContext<'ctx> {
+ /// The map of all the items parsed so far.
+ ///
+ /// It's a BTreeMap because we want the keys to be sorted to have consistent
+ /// output.
+ items: BTreeMap<ItemId, Item>,
+
+ /// The next item id to use during this bindings regeneration.
+ next_item_id: ItemId,
+
+ /// Clang USR to type map. This is needed to be able to associate types with
+ /// item ids during parsing.
+ types: HashMap<TypeKey, ItemId>,
+
+ /// A cursor to module map. Similar reason than above.
+ modules: HashMap<Cursor, ItemId>,
+
+ /// The root module, this is guaranteed to be an item of kind Module.
+ root_module: ItemId,
+
+ /// Current module being traversed.
+ current_module: ItemId,
+
+ /// A stack with the current type declarations and types we're parsing. This
+ /// is needed to avoid infinite recursion when parsing a type like:
+ ///
+ /// struct c { struct c* next; };
+ ///
+ /// This means effectively, that a type has a potential ID before knowing if
+ /// it's a correct type. But that's not important in practice.
+ ///
+ /// We could also use the `types` HashMap, but my intention with it is that
+ /// only valid types and declarations end up there, and this could
+ /// potentially break that assumption.
+ ///
+ /// FIXME: Should not be public, though... meh.
+ pub currently_parsed_types: Vec<(Cursor, ItemId)>,
+
+ /// A HashSet with all the already parsed macro names. This is done to avoid
+ /// hard errors while parsing duplicated macros, as well to allow macro
+ /// expression parsing.
+ parsed_macros: HashMap<Vec<u8>, cexpr::expr::EvalResult>,
+
+ /// The active replacements collected from replaces="xxx" annotations.
+ replacements: HashMap<Vec<String>, ItemId>,
+
+ collected_typerefs: bool,
+
+ /// Dummy structures for code generation.
+ gen_ctx: Option<&'ctx GenContext<'ctx>>,
+ span: Span,
+
+ /// The clang index for parsing.
+ index: clang::Index,
+
+ /// The translation unit for parsing.
+ translation_unit: clang::TranslationUnit,
+
+ /// The options given by the user via cli or other medium.
+ options: BindgenOptions,
+
+ /// Whether a bindgen complex was generated
+ generated_bindegen_complex: Cell<bool>,
+}
+
+impl<'ctx> BindgenContext<'ctx> {
+ /// Construct the context for the given `options`.
+ pub fn new(options: BindgenOptions) -> Self {
+ use clang_sys;
+
+ let index = clang::Index::new(false, true);
+
+ let parse_options =
+ clang_sys::CXTranslationUnit_DetailedPreprocessingRecord;
+ let translation_unit =
+ clang::TranslationUnit::parse(&index,
+ "",
+ &options.clang_args,
+ &[],
+ parse_options)
+ .expect("TranslationUnit::parse");
+
+ let root_module = Self::build_root_module(ItemId(0));
+ let mut me = BindgenContext {
+ items: Default::default(),
+ types: Default::default(),
+ modules: Default::default(),
+ next_item_id: ItemId(1),
+ root_module: root_module.id(),
+ current_module: root_module.id(),
+ currently_parsed_types: vec![],
+ parsed_macros: Default::default(),
+ replacements: Default::default(),
+ collected_typerefs: false,
+ gen_ctx: None,
+ span: DUMMY_SP,
+ index: index,
+ translation_unit: translation_unit,
+ options: options,
+ generated_bindegen_complex: Cell::new(false),
+ };
+
+ me.add_item(root_module, None, None);
+
+ me
+ }
+
+ /// Get the user-provided type chooser by reference, if any.
+ pub fn type_chooser(&self) -> Option<&TypeChooser> {
+ self.options().type_chooser.as_ref().map(|t| &**t)
+ }
+
+ /// Define a new item.
+ ///
+ /// This inserts it into the internal items set, and its type into the
+ /// internal types set.
+ pub fn add_item(&mut self,
+ item: Item,
+ declaration: Option<Cursor>,
+ location: Option<Cursor>) {
+ debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}",
+ item,
+ declaration,
+ location);
+ debug_assert!(declaration.is_some() || !item.kind().is_type() ||
+ item.kind().expect_type().is_builtin_or_named(),
+ "Adding a type without declaration?");
+
+ let id = item.id();
+ let is_type = item.kind().is_type();
+ let is_unnamed = is_type && item.expect_type().name().is_none();
+
+ // Be sure to track all the generated children under namespace, even
+ // those generated after resolving typerefs, etc.
+ if item.id() != item.parent_id() {
+ if let Some(mut parent) = self.items.get_mut(&item.parent_id()) {
+ if let Some(mut module) = parent.as_module_mut() {
+ module.children_mut().push(item.id());
+ }
+ }
+ }
+
+ let old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(), "Inserted type twice?");
+
+ // Unnamed items can have an USR, but they can't be referenced from
+ // other sites explicitly and the USR can match if the unnamed items are
+ // nested, so don't bother tracking them.
+ if is_type && declaration.is_some() {
+ let mut declaration = declaration.unwrap();
+ if !declaration.is_valid() {
+ if let Some(location) = location {
+ if location.is_template_like() {
+ declaration = location;
+ }
+ }
+ }
+ declaration = declaration.canonical();
+ if !declaration.is_valid() {
+ // This could happen, for example, with types like `int*` or
+ // similar.
+ //
+ // Fortunately, we don't care about those types being
+ // duplicated, so we can just ignore them.
+ debug!("Invalid declaration {:?} found for type {:?}",
+ declaration,
+ self.items.get(&id).unwrap().kind().expect_type());
+ return;
+ }
+
+ let key = if is_unnamed {
+ TypeKey::Declaration(declaration)
+ } else if let Some(usr) = declaration.usr() {
+ TypeKey::USR(usr)
+ } else {
+ warn!("Valid declaration with no USR: {:?}, {:?}",
+ declaration,
+ location);
+ TypeKey::Declaration(declaration)
+ };
+
+ let old = self.types.insert(key, id);
+ debug_assert_eq!(old, None);
+ }
+ }
+
+ // TODO: Move all this syntax crap to other part of the code.
+
+ /// Given that we are in the codegen phase, get the syntex context.
+ pub fn ext_cx(&self) -> &ExtCtxt<'ctx> {
+ &self.gen_ctx.expect("Not in gen phase").0
+ }
+
+ /// Given that we are in the codegen phase, get the current syntex span.
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ /// Mangles a name so it doesn't conflict with any keyword.
+ pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
+ use syntax::parse::token;
+ let ident = self.rust_ident_raw(name);
+ let token = token::Ident(ident);
+ if token.is_any_keyword() || name.contains("@") ||
+ name.contains("?") || name.contains("$") ||
+ "bool" == name {
+ let mut s = name.to_owned();
+ s = s.replace("@", "_");
+ s = s.replace("?", "_");
+ s = s.replace("$", "_");
+ s.push_str("_");
+ return Cow::Owned(s);
+ }
+ Cow::Borrowed(name)
+ }
+
+ /// Returns a mangled name as a rust identifier.
+ pub fn rust_ident(&self, name: &str) -> Ident {
+ self.rust_ident_raw(&self.rust_mangle(name))
+ }
+
+ /// Returns a mangled name as a rust identifier.
+ pub fn rust_ident_raw(&self, name: &str) -> Ident {
+ self.ext_cx().ident_of(name)
+ }
+
+ /// Iterate over all items that have been defined.
+ pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> {
+ self.items.iter()
+ }
+
+ /// Have we collected all unresolved type references yet?
+ pub fn collected_typerefs(&self) -> bool {
+ self.collected_typerefs
+ }
+
+ /// Gather all the unresolved type references.
+ fn collect_typerefs
+ (&mut self)
+ -> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> {
+ debug_assert!(!self.collected_typerefs);
+ self.collected_typerefs = true;
+ let mut typerefs = vec![];
+ for (id, ref mut item) in &mut self.items {
+ let kind = item.kind();
+ let ty = match kind.as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ match *ty.kind() {
+ TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) => {
+ typerefs.push((*id, ty.clone(), loc, parent_id));
+ }
+ _ => {}
+ };
+ }
+ typerefs
+ }
+
+ /// Collect all of our unresolved type references and resolve them.
+ fn resolve_typerefs(&mut self) {
+ let typerefs = self.collect_typerefs();
+
+ for (id, ty, loc, parent_id) in typerefs {
+ let _resolved = {
+ let resolved = Item::from_ty(&ty, loc, parent_id, self)
+ .expect("What happened?");
+ let mut item = self.items.get_mut(&id).unwrap();
+
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(resolved);
+ resolved
+ };
+
+ // Something in the STL is trolling me. I don't need this assertion
+ // right now, but worth investigating properly once this lands.
+ //
+ // debug_assert!(self.items.get(&resolved).is_some(), "How?");
+ }
+ }
+
+ /// Iterate over all items and replace any item that has been named in a
+ /// `replaces="SomeType"` annotation with the replacement type.
+ fn process_replacements(&mut self) {
+ if self.replacements.is_empty() {
+ debug!("No replacements to process");
+ return;
+ }
+
+ // FIXME: This is linear, but the replaces="xxx" annotation was already
+ // there, and for better or worse it's useful, sigh...
+ //
+ // We leverage the ResolvedTypeRef thing, though, which is cool :P.
+
+ let mut replacements = vec![];
+
+ for (id, item) in self.items.iter() {
+ if item.annotations().use_instead_of().is_some() {
+ continue;
+ }
+
+ // Calls to `canonical_name` are expensive, so eagerly filter out
+ // items that cannot be replaced.
+ let ty = match item.kind().as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ match *ty.kind() {
+ TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {}
+ TypeKind::TemplateAlias(..) |
+ TypeKind::Alias(..) => {}
+ _ => continue,
+ }
+
+ let path = item.canonical_path(self);
+ let replacement = self.replacements.get(&path[1..]);
+
+ if let Some(replacement) = replacement {
+ if replacement != id {
+ // We set this just after parsing the annotation. It's
+ // very unlikely, but this can happen.
+ if self.items.get(replacement).is_some() {
+ replacements.push((*id, *replacement));
+ }
+ }
+ }
+ }
+
+ for (id, replacement) in replacements {
+ debug!("Replacing {:?} with {:?}", id, replacement);
+
+ let new_parent = {
+ let mut item = self.items.get_mut(&id).unwrap();
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(replacement);
+ item.parent_id()
+ };
+
+
+ // Reparent the item.
+ let old_parent = self.resolve_item(replacement).parent_id();
+
+ if new_parent == old_parent {
+ continue;
+ }
+
+ if let Some(mut module) = self.items
+ .get_mut(&old_parent)
+ .unwrap()
+ .as_module_mut() {
+ // Deparent the replacement.
+ let position = module.children()
+ .iter()
+ .position(|id| *id == replacement)
+ .unwrap();
+ module.children_mut().remove(position);
+ }
+
+ if let Some(mut module) = self.items
+ .get_mut(&new_parent)
+ .unwrap()
+ .as_module_mut() {
+ module.children_mut().push(replacement);
+ }
+
+ self.items
+ .get_mut(&replacement)
+ .unwrap()
+ .set_parent_for_replacement(new_parent);
+ self.items
+ .get_mut(&id)
+ .unwrap()
+ .set_parent_for_replacement(old_parent);
+ }
+ }
+
+ /// Enter the code generation phase, invoke the given callback `cb`, and
+ /// leave the code generation phase.
+ pub fn gen<F, Out>(&mut self, cb: F) -> Out
+ where F: FnOnce(&Self) -> Out,
+ {
+ use aster::symbol::ToSymbol;
+ use syntax::ext::expand::ExpansionConfig;
+ use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan};
+ use syntax::ext::base;
+ use syntax::parse;
+ use std::mem;
+
+ let cfg = ExpansionConfig::default("xxx".to_owned());
+ let sess = parse::ParseSess::new();
+ let mut loader = base::DummyResolver;
+ let mut ctx = GenContext(base::ExtCtxt::new(&sess, cfg, &mut loader));
+
+ ctx.0.bt_push(ExpnInfo {
+ call_site: self.span,
+ callee: NameAndSpan {
+ format: MacroBang("".to_symbol()),
+ allow_internal_unstable: false,
+ span: None,
+ },
+ });
+
+ // FIXME: This is evil, we should move code generation to use a wrapper
+ // of BindgenContext instead, I guess. Even though we know it's fine
+ // because we remove it before the end of this function.
+ self.gen_ctx = Some(unsafe { mem::transmute(&ctx) });
+
+ self.assert_no_dangling_references();
+
+ if !self.collected_typerefs() {
+ self.resolve_typerefs();
+ self.process_replacements();
+ }
+
+ let ret = cb(self);
+ self.gen_ctx = None;
+ ret
+ }
+
+ /// This function trying to find any dangling references inside of `items`
+ fn assert_no_dangling_references(&self) {
+ if cfg!(feature = "assert_no_dangling_items") {
+ for _ in self.assert_no_dangling_item_traversal() {
+ // The iterator's next method does the asserting for us.
+ }
+ }
+ }
+
+ fn assert_no_dangling_item_traversal<'me>
+ (&'me self)
+ -> AssertNoDanglingItemIter<'me, 'ctx> {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ let mut roots = self.items().map(|(&id, _)| id);
+
+ let mut seen = BTreeMap::<ItemId, ItemId>::new();
+ let next_child = roots.next().map(|id| id).unwrap();
+ seen.insert(next_child, next_child);
+
+ let to_iterate = seen.iter().map(|(&id, _)| id).rev().collect();
+
+ AssertNoDanglingItemIter {
+ ctx: self,
+ seen: seen,
+ to_iterate: to_iterate,
+ }
+ }
+
+ // This deserves a comment. Builtin types don't get a valid declaration, so
+ // we can't add it to the cursor->type map.
+ //
+ // That being said, they're not generated anyway, and are few, so the
+ // duplication and special-casing is fine.
+ //
+ // If at some point we care about the memory here, probably a map TypeKind
+ // -> builtin type ItemId would be the best to improve that.
+ fn add_builtin_item(&mut self, item: Item) {
+ debug!("add_builtin_item: item = {:?}", item);
+ debug_assert!(item.kind().is_type());
+ let id = item.id();
+ let old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(), "Inserted type twice?");
+ }
+
+ fn build_root_module(id: ItemId) -> Item {
+ let module = Module::new(Some("root".into()), ModuleKind::Normal);
+ Item::new(id, None, None, id, ItemKind::Module(module))
+ }
+
+ /// Get the root module.
+ pub fn root_module(&self) -> ItemId {
+ self.root_module
+ }
+
+ /// Resolve the given `ItemId` as a type.
+ ///
+ /// Panics if there is no item for the given `ItemId` or if the resolved
+ /// item is not a `Type`.
+ pub fn resolve_type(&self, type_id: ItemId) -> &Type {
+ self.items.get(&type_id).unwrap().kind().expect_type()
+ }
+
+ /// Resolve the given `ItemId` as a type, or `None` if there is no item with
+ /// the given id.
+ ///
+ /// Panics if the id resolves to an item that is not a type.
+ pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> {
+ self.items.get(&type_id).map(|t| t.kind().expect_type())
+ }
+
+ /// Resolve the given `ItemId` into an `Item`, or `None` if no such item
+ /// exists.
+ pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> {
+ self.items.get(&item_id)
+ }
+
+ /// Resolve the given `ItemId` into an `Item`.
+ ///
+ /// Panics if the given id does not resolve to any item.
+ pub fn resolve_item(&self, item_id: ItemId) -> &Item {
+ match self.items.get(&item_id) {
+ Some(item) => item,
+ None => panic!("Not an item: {:?}", item_id),
+ }
+ }
+
+ /// Get the current module.
+ pub fn current_module(&self) -> ItemId {
+ self.current_module
+ }
+
+ /// This is one of the hackiest methods in all the parsing code. This method
+ /// is used to allow having templates with another argument names instead of
+ /// the canonical ones.
+ ///
+ /// This is surprisingly difficult to do with libclang, due to the fact that
+ /// partial template specializations don't provide explicit template
+ /// argument information.
+ ///
+ /// The only way to do this as far as I know, is inspecting manually the
+ /// AST, looking for TypeRefs inside. This, unfortunately, doesn't work for
+ /// more complex cases, see the comment on the assertion below.
+ ///
+ /// To see an example of what this handles:
+ ///
+ /// ```c++
+ /// template<typename T>
+ /// class Incomplete {
+ /// T p;
+ /// };
+ ///
+ /// template<typename U>
+ /// class Foo {
+ /// Incomplete<U> bar;
+ /// };
+ /// ```
+ fn build_template_wrapper(&mut self,
+ with_id: ItemId,
+ wrapping: ItemId,
+ parent_id: ItemId,
+ ty: &clang::Type,
+ location: clang::Cursor,
+ declaration: clang::Cursor)
+ -> ItemId {
+ use clang_sys::*;
+ let mut args = vec![];
+ location.visit(|c| {
+ if c.kind() == CXCursor_TypeRef {
+ // The `with_id` id will potentially end up unused if we give up
+ // on this type (for example, its a tricky partial template
+ // specialization), so if we pass `with_id` as the parent, it is
+ // potentially a dangling reference. Instead, use the canonical
+ // template declaration as the parent. It is already parsed and
+ // has a known-resolvable `ItemId`.
+ let new_ty = Item::from_ty_or_ref(c.cur_type(),
+ Some(c),
+ Some(wrapping),
+ self);
+ args.push(new_ty);
+ }
+ CXChildVisit_Continue
+ });
+
+ let item = {
+ let wrapping_type = self.resolve_type(wrapping);
+ if let TypeKind::Comp(ref ci) = *wrapping_type.kind() {
+ let old_args = ci.template_args();
+
+ // The following assertion actually fails with partial template
+ // specialization. But as far as I know there's no way at all to
+ // grab the specialized types from neither the AST or libclang,
+ // which sucks. The same happens for specialized type alias
+ // template declarations, where we have that ugly hack up there.
+ //
+ // This flaw was already on the old parser, but I now think it
+ // has no clear solution (apart from patching libclang to
+ // somehow expose them, of course).
+ //
+ // For an easy example in which there's no way at all of getting
+ // the `int` type, except manually parsing the spelling:
+ //
+ // template<typename T, typename U>
+ // class Incomplete {
+ // T d;
+ // U p;
+ // };
+ //
+ // template<typename U>
+ // class Foo {
+ // Incomplete<U, int> bar;
+ // };
+ //
+ // debug_assert_eq!(old_args.len(), args.len());
+ //
+ // That being said, this is not so common, so just error! and
+ // hope for the best, returning the previous type, who knows.
+ if old_args.len() != args.len() {
+ error!("Found partial template specialization, \
+ expect dragons!");
+ return wrapping;
+ }
+ } else {
+ assert_eq!(declaration.kind(),
+ ::clang_sys::CXCursor_TypeAliasTemplateDecl,
+ "Expected wrappable type");
+ }
+
+ let type_kind = TypeKind::TemplateRef(wrapping, args);
+ let name = ty.spelling();
+ let name = if name.is_empty() { None } else { Some(name) };
+ let ty = Type::new(name,
+ ty.fallible_layout().ok(),
+ type_kind,
+ ty.is_const());
+ Item::new(with_id, None, None, parent_id, ItemKind::Type(ty))
+ };
+
+ // Bypass all the validations in add_item explicitly.
+ debug!("build_template_wrapper: inserting item: {:?}", item);
+ debug_assert!(with_id == item.id());
+ self.items.insert(with_id, item);
+ with_id
+ }
+
+ /// Looks up for an already resolved type, either because it's builtin, or
+ /// because we already have it in the map.
+ pub fn builtin_or_resolved_ty(&mut self,
+ with_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>)
+ -> Option<ItemId> {
+ use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
+ debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
+ ty,
+ location,
+ parent_id);
+ let mut declaration = ty.declaration();
+ if !declaration.is_valid() {
+ if let Some(location) = location {
+ if location.is_template_like() {
+ declaration = location;
+ }
+ }
+ }
+ let canonical_declaration = declaration.canonical();
+ if canonical_declaration.is_valid() {
+ let id = self.types
+ .get(&TypeKey::Declaration(canonical_declaration))
+ .map(|id| *id)
+ .or_else(|| {
+ canonical_declaration.usr()
+ .and_then(|usr| self.types.get(&TypeKey::USR(usr)))
+ .map(|id| *id)
+ });
+ if let Some(id) = id {
+ debug!("Already resolved ty {:?}, {:?}, {:?} {:?}",
+ id,
+ declaration,
+ ty,
+ location);
+
+ // If the declaration existed, we *might* be done, but it's not
+ // the case for class templates, where the template arguments
+ // may vary.
+ //
+ // In this case, we create a TemplateRef with the new template
+ // arguments, pointing to the canonical template.
+ //
+ // Note that we only do it if parent_id is some, and we have a
+ // location for building the new arguments, the template
+ // argument names don't matter in the global context.
+ if declaration.is_template_like() &&
+ *ty != canonical_declaration.cur_type() &&
+ location.is_some() &&
+ parent_id.is_some() {
+ // For specialized type aliases, there's no way to get the
+ // template parameters as of this writing (for a struct
+ // specialization we wouldn't be in this branch anyway).
+ //
+ // Explicitly return `None` if there aren't any
+ // unspecialized parameters (contains any `TypeRef`) so we
+ // resolve the canonical type if there is one and it's
+ // exposed.
+ //
+ // This is _tricky_, I know :(
+ if declaration.kind() == CXCursor_TypeAliasTemplateDecl &&
+ !location.unwrap().contains_cursor(CXCursor_TypeRef) &&
+ ty.canonical_type().is_valid_and_exposed() {
+ return None;
+ }
+
+ return Some(self.build_template_wrapper(with_id,
+ id,
+ parent_id.unwrap(),
+ ty,
+ location.unwrap(),
+ declaration));
+ }
+
+ return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
+ }
+ }
+
+ debug!("Not resolved, maybe builtin?");
+
+ // Else, build it.
+ self.build_builtin_ty(ty, declaration)
+ }
+
+ // This is unfortunately a lot of bloat, but is needed to properly track
+ // constness et. al.
+ //
+ // We should probably make the constness tracking separate, so it doesn't
+ // bloat that much, but hey, we already bloat the heck out of builtin types.
+ fn build_ty_wrapper(&mut self,
+ with_id: ItemId,
+ wrapped_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type)
+ -> ItemId {
+ let spelling = ty.spelling();
+ let is_const = ty.is_const();
+ let layout = ty.fallible_layout().ok();
+ let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let item = Item::new(with_id,
+ None,
+ None,
+ parent_id.unwrap_or(self.current_module),
+ ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ with_id
+ }
+
+ /// Returns the next item id to be used for an item.
+ pub fn next_item_id(&mut self) -> ItemId {
+ let ret = self.next_item_id;
+ self.next_item_id = ItemId(self.next_item_id.0 + 1);
+ ret
+ }
+
+ fn build_builtin_ty(&mut self,
+ ty: &clang::Type,
+ _declaration: Cursor)
+ -> Option<ItemId> {
+ use clang_sys::*;
+ let type_kind = match ty.kind() {
+ CXType_NullPtr => TypeKind::NullPtr,
+ CXType_Void => TypeKind::Void,
+ CXType_Bool => TypeKind::Int(IntKind::Bool),
+ CXType_Int => TypeKind::Int(IntKind::Int),
+ CXType_UInt => TypeKind::Int(IntKind::UInt),
+ CXType_SChar | CXType_Char_S => TypeKind::Int(IntKind::Char),
+ CXType_UChar | CXType_Char_U => TypeKind::Int(IntKind::UChar),
+ CXType_Short => TypeKind::Int(IntKind::Short),
+ CXType_UShort => TypeKind::Int(IntKind::UShort),
+ CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16),
+ CXType_Char32 => TypeKind::Int(IntKind::U32),
+ CXType_Long => TypeKind::Int(IntKind::Long),
+ CXType_ULong => TypeKind::Int(IntKind::ULong),
+ CXType_LongLong => TypeKind::Int(IntKind::LongLong),
+ CXType_ULongLong => TypeKind::Int(IntKind::ULongLong),
+ CXType_Int128 => TypeKind::Int(IntKind::I128),
+ CXType_UInt128 => TypeKind::Int(IntKind::U128),
+ CXType_Float => TypeKind::Float(FloatKind::Float),
+ CXType_Double => TypeKind::Float(FloatKind::Double),
+ CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble),
+ CXType_Float128 => TypeKind::Float(FloatKind::Float128),
+ CXType_Complex => {
+ let float_type = ty.elem_type()
+ .expect("Not able to resolve complex type?");
+ let float_kind = match float_type.kind() {
+ CXType_Float => FloatKind::Float,
+ CXType_Double => FloatKind::Double,
+ CXType_LongDouble => FloatKind::LongDouble,
+ _ => panic!("Non floating-type complex?"),
+ };
+ TypeKind::Complex(float_kind)
+ }
+ _ => return None,
+ };
+
+ let spelling = ty.spelling();
+ let is_const = ty.is_const();
+ let layout = ty.fallible_layout().ok();
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let id = self.next_item_id();
+ let item =
+ Item::new(id, None, None, self.root_module, ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ Some(id)
+ }
+
+ /// Get the current Clang translation unit that is being processed.
+ pub fn translation_unit(&self) -> &clang::TranslationUnit {
+ &self.translation_unit
+ }
+
+ /// Have we parsed the macro named `macro_name` already?
+ pub fn parsed_macro(&self, macro_name: &[u8]) -> bool {
+ self.parsed_macros.contains_key(macro_name)
+ }
+
+ /// Get the currently parsed macros.
+ pub fn parsed_macros(&self) -> &HashMap<Vec<u8>, cexpr::expr::EvalResult> {
+ debug_assert!(!self.in_codegen_phase());
+ &self.parsed_macros
+ }
+
+ /// Mark the macro named `macro_name` as parsed.
+ pub fn note_parsed_macro(&mut self,
+ id: Vec<u8>,
+ value: cexpr::expr::EvalResult) {
+ self.parsed_macros.insert(id, value);
+ }
+
+ /// Are we in the codegen phase?
+ pub fn in_codegen_phase(&self) -> bool {
+ self.gen_ctx.is_some()
+ }
+
+ /// Mark the type with the given `name` as replaced by the type with id
+ /// `potential_ty`.
+ ///
+ /// Replacement types are declared using the `replaces="xxx"` annotation,
+ /// and implies that the original type is hidden.
+ pub fn replace(&mut self, name: &[String], potential_ty: ItemId) {
+ match self.replacements.entry(name.into()) {
+ hash_map::Entry::Vacant(entry) => {
+ debug!("Defining replacement for {:?} as {:?}",
+ name,
+ potential_ty);
+ entry.insert(potential_ty);
+ }
+ hash_map::Entry::Occupied(occupied) => {
+ warn!("Replacement for {:?} already defined as {:?}; \
+ ignoring duplicate replacement definition as {:?}",
+ name,
+ occupied.get(),
+ potential_ty);
+ }
+ }
+ }
+
+ /// Is the item with the given `name` hidden? Or is the item with the given
+ /// `name` and `id` replaced by another type, and effectively hidden?
+ pub fn hidden_by_name(&self, path: &[String], id: ItemId) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.hidden_types.matches(&path[1..].join("::")) ||
+ self.is_replaced_type(path, id)
+ }
+
+ /// Has the item with the given `name` and `id` been replaced by another
+ /// type?
+ pub fn is_replaced_type(&self, path: &[String], id: ItemId) -> bool {
+ match self.replacements.get(path) {
+ Some(replaced_by) if *replaced_by != id => true,
+ _ => false,
+ }
+ }
+
+ /// Is the type with the given `name` marked as opaque?
+ pub fn opaque_by_name(&self, path: &[String]) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.opaque_types.matches(&path[1..].join("::"))
+ }
+
+ /// Get the options used to configure this bindgen context.
+ pub fn options(&self) -> &BindgenOptions {
+ &self.options
+ }
+
+ /// Tokenizes a namespace cursor in order to get the name and kind of the
+ /// namespace,
+ fn tokenize_namespace(&self,
+ cursor: &clang::Cursor)
+ -> (Option<String>, ModuleKind) {
+ assert_eq!(cursor.kind(), ::clang_sys::CXCursor_Namespace,
+ "Be a nice person");
+ let tokens = match self.translation_unit.tokens(&cursor) {
+ Some(tokens) => tokens,
+ None => return (None, ModuleKind::Normal),
+ };
+
+ let mut iter = tokens.iter();
+ let mut kind = ModuleKind::Normal;
+ let mut found_namespace_keyword = false;
+ let mut module_name = None;
+ while let Some(token) = iter.next() {
+ match &*token.spelling {
+ "inline" => {
+ assert!(!found_namespace_keyword);
+ assert!(kind != ModuleKind::Inline);
+ kind = ModuleKind::Inline;
+ }
+ "namespace" => {
+ found_namespace_keyword = true;
+ }
+ "{" => {
+ assert!(found_namespace_keyword);
+ break;
+ }
+ name if found_namespace_keyword => {
+ module_name = Some(name.to_owned());
+ break;
+ }
+ _ => {
+ panic!("Unknown token while processing namespace: {:?}",
+ token);
+ }
+ }
+ };
+
+ (module_name, kind)
+ }
+
+ /// Given a CXCursor_Namespace cursor, return the item id of the
+ /// corresponding module, or create one on the fly.
+ pub fn module(&mut self, cursor: clang::Cursor) -> ItemId {
+ use clang_sys::*;
+ assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person");
+ let cursor = cursor.canonical();
+ if let Some(id) = self.modules.get(&cursor) {
+ return *id;
+ }
+
+ let (module_name, kind) = self.tokenize_namespace(&cursor);
+
+ let module_id = self.next_item_id();
+ let module = Module::new(module_name, kind);
+ let module = Item::new(module_id,
+ None,
+ None,
+ self.current_module,
+ ItemKind::Module(module));
+
+ self.modules.insert(cursor, module.id());
+
+ self.add_item(module, None, None);
+
+ module_id
+ }
+
+ /// Start traversing the module with the given `module_id`, invoke the
+ /// callback `cb`, and then return to traversing the original module.
+ pub fn with_module<F>(&mut self, module_id: ItemId, cb: F)
+ where F: FnOnce(&mut Self),
+ {
+ debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
+
+ let previous_id = self.current_module;
+ self.current_module = module_id;
+
+ cb(self);
+
+ self.current_module = previous_id;
+ }
+
+ /// Iterate over all (explicitly or transitively) whitelisted items.
+ ///
+ /// If no items are explicitly whitelisted, then all items are considered
+ /// whitelisted.
+ pub fn whitelisted_items<'me>(&'me self)
+ -> WhitelistedItemsIter<'me, 'ctx> {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ let roots = self.items()
+ .filter(|&(_, item)| {
+ // If nothing is explicitly whitelisted, then everything is fair
+ // game.
+ if self.options().whitelisted_types.is_empty() &&
+ self.options().whitelisted_functions.is_empty() &&
+ self.options().whitelisted_vars.is_empty() {
+ return true;
+ }
+
+ // If this is a type that explicitly replaces another, we assume
+ // you know what you're doing.
+ if item.annotations().use_instead_of().is_some() {
+ return true;
+ }
+
+ let name = item.canonical_path(self)[1..].join("::");
+ debug!("whitelisted_items: testing {:?}", name);
+ match *item.kind() {
+ ItemKind::Module(..) => true,
+ ItemKind::Function(_) => {
+ self.options().whitelisted_functions.matches(&name)
+ }
+ ItemKind::Var(_) => {
+ self.options().whitelisted_vars.matches(&name)
+ }
+ ItemKind::Type(ref ty) => {
+ if self.options().whitelisted_types.matches(&name) {
+ return true;
+ }
+
+ let parent = self.resolve_item(item.parent_id());
+ if parent.is_module() {
+ let mut prefix_path = parent.canonical_path(self);
+
+ // Unnamed top-level enums are special and we
+ // whitelist them via the `whitelisted_vars` filter,
+ // since they're effectively top-level constants,
+ // and there's no way for them to be referenced
+ // consistently.
+ if let TypeKind::Enum(ref enum_) = *ty.kind() {
+ if ty.name().is_none() &&
+ enum_.variants().iter().any(|variant| {
+ prefix_path.push(variant.name().into());
+ let name = prefix_path[1..].join("::");
+ prefix_path.pop().unwrap();
+ self.options()
+ .whitelisted_vars
+ .matches(&name)
+ }) {
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+ }
+ })
+ .map(|(&id, _)| id);
+
+ let seen: ItemSet = roots.collect();
+
+ // The .rev() preserves the expected ordering traversal, resulting in
+ // more stable-ish bindgen-generated names for anonymous types (like
+ // unions).
+ let to_iterate = seen.iter().cloned().rev().collect();
+
+ WhitelistedItemsIter {
+ ctx: self,
+ seen: seen,
+ to_iterate: to_iterate,
+ }
+ }
+
+ /// Convenient method for getting the prefix to use for most traits in
+ /// codegen depending on the `use_core` option.
+ pub fn trait_prefix(&self) -> Ident {
+ if self.options().use_core {
+ self.rust_ident_raw("core")
+ } else {
+ self.rust_ident_raw("std")
+ }
+ }
+
+ /// Call if a binden complex is generated
+ pub fn generated_bindegen_complex(&self) {
+ self.generated_bindegen_complex.set(true)
+ }
+
+ /// Whether we need to generate the binden complex type
+ pub fn need_bindegen_complex_type(&self) -> bool {
+ self.generated_bindegen_complex.get()
+ }
+}
+
+/// An iterator over whitelisted items.
+///
+/// See `BindgenContext::whitelisted_items` for more information.
+pub struct WhitelistedItemsIter<'ctx, 'gen>
+ where 'gen: 'ctx,
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // The set of whitelisted items we have seen. If you think of traversing
+ // whitelisted items like GC tracing, this is the mark bits, and contains
+ // both black and gray items.
+ seen: ItemSet,
+
+ // The set of whitelisted items that we have seen but have yet to iterate
+ // over and collect transitive references from. To return to the GC analogy,
+ // this is the mark stack, containing the set of gray items which we have
+ // not finished tracing yet.
+ to_iterate: Vec<ItemId>,
+}
+
+impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
+ where 'gen: 'ctx,
+{
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let id = match self.to_iterate.pop() {
+ None => return None,
+ Some(id) => id,
+ };
+
+ debug_assert!(self.seen.contains(&id));
+ debug_assert!(self.ctx.items.contains_key(&id));
+
+ let mut sub_types = ItemSet::new();
+ id.collect_types(self.ctx, &mut sub_types, &());
+
+ for id in sub_types {
+ if self.seen.insert(id) {
+ self.to_iterate.push(id);
+ }
+ }
+
+ Some(id)
+ }
+}
+
+/// An iterator to find any dangling items.
+///
+/// See `BindgenContext::assert_no_dangling_item_traversal` for more
+/// information.
+pub struct AssertNoDanglingItemIter<'ctx, 'gen>
+ where 'gen: 'ctx,
+{
+ ctx: &'ctx BindgenContext<'gen>,
+ seen: BTreeMap<ItemId, ItemId>,
+ to_iterate: VecDeque<ItemId>,
+}
+
+impl<'ctx, 'gen> Iterator for AssertNoDanglingItemIter<'ctx, 'gen>
+ where 'gen: 'ctx,
+{
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let id = match self.to_iterate.pop_front() {
+ None => {
+ // We've traversed everything reachable from the previous
+ // root(s), see if we have any more roots.
+ match self.ctx
+ .items()
+ .filter(|&(id, _)| !self.seen.contains_key(id))
+ .next()
+ .map(|(id, _)| *id) {
+ None => return None,
+ Some(id) => {
+ // This is a new root.
+ self.seen.insert(id, id);
+ id
+ }
+ }
+ }
+ Some(id) => id,
+ };
+
+ let mut sub_types = ItemSet::new();
+ id.collect_types(self.ctx, &mut sub_types, &());
+
+ if self.ctx.resolve_item_fallible(id).is_none() {
+ let mut path = vec![];
+ let mut current = id;
+ loop {
+ let predecessor = *self.seen
+ .get(&current)
+ .expect("We know we found this item id, so it must have a \
+ predecessor");
+ if predecessor == current {
+ break;
+ }
+ path.push(predecessor);
+ current = predecessor;
+ }
+ path.reverse();
+ panic!("Found reference to dangling id = {:?}\nvia path = {:?}",
+ id,
+ path);
+ }
+
+ for sub_id in sub_types {
+ if self.seen.insert(sub_id, id).is_none() {
+ // We've never visited this sub item before.
+ self.to_iterate.push_back(sub_id);
+ }
+ }
+
+ Some(id)
+ }
+}
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
new file mode 100644
index 00000000..d13a8117
--- /dev/null
+++ b/src/ir/derive.rs
@@ -0,0 +1,67 @@
+//! Traits for determining whether we can derive traits for a thing or not.
+
+use super::context::BindgenContext;
+
+/// A trait that encapsulates the logic for whether or not we can derive `Debug`
+/// for a given thing.
+///
+/// This should ideally be a no-op that just returns `true`, but instead needs
+/// to be a recursive method that checks whether all the proper members can
+/// derive debug or not, because of the limit rust has on 32 items as max in the
+/// array.
+pub trait CanDeriveDebug {
+ /// Implementations can define this type to get access to any extra
+ /// information required to determine whether they can derive `Debug`. If
+ /// extra information is unneeded, then this should simply be the unit type.
+ type Extra;
+
+ /// Return `true` if `Debug` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_debug(&self,
+ ctx: &BindgenContext,
+ extra: Self::Extra)
+ -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Copy`
+/// for a given thing.
+pub trait CanDeriveCopy<'a> {
+ /// Implementations can define this type to get access to any extra
+ /// information required to determine whether they can derive `Copy`. If
+ /// extra information is unneeded, then this should simply be the unit type.
+ type Extra;
+
+ /// Return `true` if `Copy` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_copy(&'a self,
+ ctx: &'a BindgenContext,
+ extra: Self::Extra)
+ -> bool;
+
+ /// For some reason, deriving copies of an array of a type that is not known
+ /// to be `Copy` is a compile error. e.g.:
+ ///
+ /// ```rust
+ /// #[derive(Copy, Clone)]
+ /// struct A<T> {
+ /// member: T,
+ /// }
+ /// ```
+ ///
+ /// is fine, while:
+ ///
+ /// ```rust,ignore
+ /// #[derive(Copy, Clone)]
+ /// struct A<T> {
+ /// member: [T; 1],
+ /// }
+ /// ```
+ ///
+ /// is an error.
+ ///
+ /// That's the whole point of the existence of `can_derive_copy_in_array`.
+ fn can_derive_copy_in_array(&'a self,
+ ctx: &'a BindgenContext,
+ extra: Self::Extra)
+ -> bool;
+}
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
new file mode 100644
index 00000000..ca4e77db
--- /dev/null
+++ b/src/ir/enum_ty.rs
@@ -0,0 +1,183 @@
+//! Intermediate representation for C/C++ enumerations.
+
+use clang;
+use ir::annotations::Annotations;
+use parse::{ClangItemParser, ParseError};
+use super::context::{BindgenContext, ItemId};
+use super::item::Item;
+use super::ty::TypeKind;
+
+/// An enum representing custom handling that can be given to a variant.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum EnumVariantCustomBehavior {
+ /// This variant will be constified, that is, forced to generate a constant.
+ Constify,
+ /// This variant will be hidden entirely from the resulting enum.
+ Hide,
+}
+
+/// A C/C++ enumeration.
+#[derive(Debug)]
+pub struct Enum {
+ /// The representation used for this enum; it should be an `IntKind` type or
+ /// an alias to one.
+ ///
+ /// It's `None` if the enum is a forward declaration and isn't defined
+ /// anywhere else, see `tests/headers/func_ptr_in_struct.h`.
+ repr: Option<ItemId>,
+
+ /// The different variants, with explicit values.
+ variants: Vec<EnumVariant>,
+}
+
+impl Enum {
+ /// Construct a new `Enum` with the given representation and variants.
+ pub fn new(repr: Option<ItemId>, variants: Vec<EnumVariant>) -> Self {
+ Enum {
+ repr: repr,
+ variants: variants,
+ }
+ }
+
+ /// Get this enumeration's representation.
+ pub fn repr(&self) -> Option<ItemId> {
+ self.repr
+ }
+
+ /// Get this enumeration's variants.
+ pub fn variants(&self) -> &[EnumVariant] {
+ &self.variants
+ }
+
+ /// Construct an enumeration from the given Clang type.
+ pub fn from_ty(ty: &clang::Type,
+ ctx: &mut BindgenContext)
+ -> Result<Self, ParseError> {
+ use clang_sys::*;
+ if ty.kind() != CXType_Enum {
+ return Err(ParseError::Continue);
+ }
+
+ let declaration = ty.declaration().canonical();
+ let repr = declaration.enum_type()
+ .and_then(|et| Item::from_ty(&et, None, None, ctx).ok());
+ let mut variants = vec![];
+
+ // Assume signedness since the default type by the C standard is an int.
+ let is_signed =
+ repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx))
+ .map_or(true, |ty| {
+ match *ty.kind() {
+ TypeKind::Int(ref int_kind) => int_kind.is_signed(),
+ ref other => {
+ panic!("Since when enums can be non-integers? {:?}",
+ other)
+ }
+ }
+ });
+
+ let type_name = ty.spelling();
+ let type_name = if type_name.is_empty() { None } else { Some(type_name) };
+ let type_name = type_name.as_ref().map(String::as_str);
+
+ declaration.visit(|cursor| {
+ if cursor.kind() == CXCursor_EnumConstantDecl {
+ let value = if is_signed {
+ cursor.enum_val_signed().map(EnumVariantValue::Signed)
+ } else {
+ cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
+ };
+ if let Some(val) = value {
+ let name = cursor.spelling();
+ let custom_behavior = ctx.type_chooser()
+ .and_then(|t| {
+ t.enum_variant_behavior(type_name, &name, val)
+ })
+ .or_else(|| {
+ Annotations::new(&cursor).and_then(|anno| {
+ if anno.hide() {
+ Some(EnumVariantCustomBehavior::Hide)
+ } else if anno.constify_enum_variant() {
+ Some(EnumVariantCustomBehavior::Constify)
+ } else {
+ None
+ }
+ })
+ });
+
+ let comment = cursor.raw_comment();
+ variants.push(
+ EnumVariant::new(name, comment, val, custom_behavior));
+ }
+ }
+ CXChildVisit_Continue
+ });
+ Ok(Enum::new(repr, variants))
+ }
+}
+
+/// A single enum variant, to be contained only in an enum.
+#[derive(Debug)]
+pub struct EnumVariant {
+ /// The name of the variant.
+ name: String,
+
+ /// An optional doc comment.
+ comment: Option<String>,
+
+ /// The integer value of the variant.
+ val: EnumVariantValue,
+
+ /// The custom behavior this variant may have, if any.
+ custom_behavior: Option<EnumVariantCustomBehavior>,
+}
+
+/// A constant value assigned to an enumeration variant.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum EnumVariantValue {
+ /// A signed constant.
+ Signed(i64),
+
+ /// An unsigned constant.
+ Unsigned(u64),
+}
+
+impl EnumVariant {
+ /// Construct a new enumeration variant from the given parts.
+ pub fn new(name: String,
+ comment: Option<String>,
+ val: EnumVariantValue,
+ custom_behavior: Option<EnumVariantCustomBehavior>)
+ -> Self {
+ EnumVariant {
+ name: name,
+ comment: comment,
+ val: val,
+ custom_behavior: custom_behavior,
+ }
+ }
+
+ /// Get this variant's name.
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this variant's value.
+ pub fn val(&self) -> EnumVariantValue {
+ self.val
+ }
+
+ /// Returns whether this variant should be enforced to be a constant by code
+ /// generation.
+ pub fn force_constification(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Constify)
+ }
+
+ /// Returns whether the current variant should be hidden completely from the
+ /// resulting rust enum.
+ pub fn hidden(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Hide)
+ }
+}
diff --git a/src/ir/function.rs b/src/ir/function.rs
new file mode 100644
index 00000000..50c442db
--- /dev/null
+++ b/src/ir/function.rs
@@ -0,0 +1,318 @@
+//! Intermediate representation for C/C++ functions and methods.
+
+use clang;
+use clang_sys::CXCallingConv;
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+use super::context::{BindgenContext, ItemId};
+use super::item::Item;
+use super::ty::TypeKind;
+use super::type_collector::{ItemSet, TypeCollector};
+use syntax::abi;
+
+/// A function declaration, with a signature, arguments, and argument names.
+///
+/// The argument names vector must be the same length as the ones in the
+/// signature.
+#[derive(Debug)]
+pub struct Function {
+ /// The name of this function.
+ name: String,
+
+ /// The mangled name, that is, the symbol.
+ mangled_name: Option<String>,
+
+ /// The id pointing to the current function signature.
+ signature: ItemId,
+
+ /// The doc comment on the function, if any.
+ comment: Option<String>,
+}
+
+impl Function {
+ /// Construct a new function.
+ pub fn new(name: String,
+ mangled_name: Option<String>,
+ sig: ItemId,
+ comment: Option<String>)
+ -> Self {
+ Function {
+ name: name,
+ mangled_name: mangled_name,
+ signature: sig,
+ comment: comment,
+ }
+ }
+
+ /// Get this function's name.
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this function's name.
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+
+ /// Get this function's signature.
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+}
+
+/// A function signature.
+#[derive(Debug)]
+pub struct FunctionSig {
+ /// The return type of the function.
+ return_type: ItemId,
+
+ /// The type of the arguments, optionally with the name of the argument when
+ /// declared.
+ argument_types: Vec<(Option<String>, ItemId)>,
+
+ /// Whether this function is variadic.
+ is_variadic: bool,
+
+ /// The ABI of this function.
+ abi: abi::Abi,
+}
+
+fn get_abi(cc: CXCallingConv) -> abi::Abi {
+ use clang_sys::*;
+ match cc {
+ CXCallingConv_Default => abi::Abi::C,
+ CXCallingConv_C => abi::Abi::C,
+ CXCallingConv_X86StdCall => abi::Abi::Stdcall,
+ CXCallingConv_X86FastCall => abi::Abi::Fastcall,
+ CXCallingConv_AAPCS => abi::Abi::Aapcs,
+ CXCallingConv_X86_64Win64 => abi::Abi::Win64,
+ other => panic!("unsupported calling convention: {:?}", other),
+ }
+}
+
+/// Get the mangled name for the cursor's referent.
+pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
+ // We early return here because libclang may crash in some case
+ // if we pass in a variable inside a partial specialized template.
+ // See servo/rust-bindgen#67.
+ if cursor.is_in_non_fully_specialized_template() {
+ return None;
+ }
+
+ let mut mangling = cursor.mangling();
+ if mangling.is_empty() {
+ return None;
+ }
+
+ // Try to undo backend linkage munging (prepended _, generally)
+ if cfg!(target_os = "macos") {
+ mangling.remove(0);
+ }
+
+ Some(mangling)
+}
+
+impl FunctionSig {
+ /// Construct a new function signature.
+ pub fn new(return_type: ItemId,
+ arguments: Vec<(Option<String>, ItemId)>,
+ is_variadic: bool,
+ abi: abi::Abi)
+ -> Self {
+ FunctionSig {
+ return_type: return_type,
+ argument_types: arguments,
+ is_variadic: is_variadic,
+ abi: abi,
+ }
+ }
+
+ /// Construct a new function signature from the given Clang type.
+ pub fn from_ty(ty: &clang::Type,
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext)
+ -> Result<Self, ParseError> {
+ use clang_sys::*;
+ debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
+
+ // Skip function templates
+ if cursor.kind() == CXCursor_FunctionTemplate {
+ return Err(ParseError::Continue);
+ }
+
+ // Don't parse operatorxx functions in C++
+ let spelling = cursor.spelling();
+ if spelling.starts_with("operator") {
+ return Err(ParseError::Continue);
+ }
+
+ let cursor = if cursor.is_valid() {
+ *cursor
+ } else {
+ ty.declaration()
+ };
+
+ let mut args: Vec<_> = match cursor.kind() {
+ CXCursor_FunctionDecl |
+ CXCursor_Constructor |
+ CXCursor_CXXMethod => {
+ // For CXCursor_FunctionDecl, cursor.args() is the reliable way
+ // to get parameter names and types.
+ cursor.args()
+ .unwrap()
+ .iter()
+ .map(|arg| {
+ let arg_ty = arg.cur_type();
+ let name = arg.spelling();
+ let name =
+ if name.is_empty() { None } else { Some(name) };
+ let ty = Item::from_ty(&arg_ty, Some(*arg), None, ctx)
+ .expect("Argument?");
+ (name, ty)
+ })
+ .collect()
+ }
+ _ => {
+ // For non-CXCursor_FunctionDecl, visiting the cursor's children
+ // is the only reliable way to get parameter names.
+ let mut args = vec![];
+ cursor.visit(|c| {
+ if c.kind() == CXCursor_ParmDecl {
+ let ty =
+ Item::from_ty(&c.cur_type(), Some(c), None, ctx)
+ .expect("ParmDecl?");
+ let name = c.spelling();
+ let name =
+ if name.is_empty() { None } else { Some(name) };
+ args.push((name, ty));
+ }
+ CXChildVisit_Continue
+ });
+ args
+ }
+ };
+
+ let is_method = cursor.kind() == CXCursor_CXXMethod;
+ let is_constructor = cursor.kind() == CXCursor_Constructor;
+ if (is_constructor || is_method) &&
+ cursor.lexical_parent() != cursor.semantic_parent() {
+ // Only parse constructors once.
+ return Err(ParseError::Continue);
+ }
+
+ if is_method || is_constructor {
+ let is_const = is_method && cursor.method_is_const();
+ let is_virtual = is_method && cursor.method_is_virtual();
+ let is_static = is_method && cursor.method_is_static();
+ if !is_static && !is_virtual {
+ let class = Item::parse(cursor.semantic_parent(), None, ctx)
+ .expect("Expected to parse the class");
+ let ptr =
+ Item::builtin_type(TypeKind::Pointer(class), is_const, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ } else if is_virtual {
+ let void = Item::builtin_type(TypeKind::Void, false, ctx);
+ let ptr =
+ Item::builtin_type(TypeKind::Pointer(void), false, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ }
+ }
+
+ let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue));
+ let ret = try!(Item::from_ty(&ty_ret_type, None, None, ctx));
+ let abi = get_abi(ty.call_conv());
+
+ Ok(Self::new(ret, args, ty.is_variadic(), abi))
+ }
+
+ /// Get this function signature's return type.
+ pub fn return_type(&self) -> ItemId {
+ self.return_type
+ }
+
+ /// Get this function signature's argument (name, type) pairs.
+ pub fn argument_types(&self) -> &[(Option<String>, ItemId)] {
+ &self.argument_types
+ }
+
+ /// Get this function signature's ABI.
+ pub fn abi(&self) -> abi::Abi {
+ self.abi
+ }
+
+ /// Is this function signature variadic?
+ pub fn is_variadic(&self) -> bool {
+ // Clang reports some functions as variadic when they *might* be
+ // variadic. We do the argument check because rust doesn't codegen well
+ // variadic functions without an initial argument.
+ self.is_variadic && !self.argument_types.is_empty()
+ }
+}
+
+impl ClangSubItemParser for Function {
+ fn parse(cursor: clang::Cursor,
+ context: &mut BindgenContext)
+ -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ match cursor.kind() {
+ // FIXME(emilio): Generate destructors properly.
+ CXCursor_FunctionDecl |
+ CXCursor_Constructor |
+ CXCursor_CXXMethod => {}
+ _ => return Err(ParseError::Continue),
+ };
+
+ debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
+
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return Err(ParseError::Continue);
+ }
+
+ if cursor.access_specifier() == CX_CXXPrivate {
+ return Err(ParseError::Continue);
+ }
+
+ if cursor.is_inlined_function() {
+ return Err(ParseError::Continue);
+ }
+
+ let linkage = cursor.linkage();
+ if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
+ return Err(ParseError::Continue);
+ }
+
+ // Grab the signature using Item::from_ty.
+ let sig = try!(Item::from_ty(&cursor.cur_type(),
+ Some(cursor),
+ None,
+ context));
+
+ let name = cursor.spelling();
+ assert!(!name.is_empty(), "Empty function name?");
+
+ let mut mangled_name = cursor_mangling(&cursor);
+ if mangled_name.as_ref() == Some(&name) {
+ mangled_name = None;
+ }
+
+ let comment = cursor.raw_comment();
+
+ let function = Self::new(name, mangled_name, sig, comment);
+ Ok(ParseResult::New(function, Some(cursor)))
+ }
+}
+
+impl TypeCollector for FunctionSig {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ _context: &BindgenContext,
+ types: &mut ItemSet,
+ _item: &Item) {
+ types.insert(self.return_type());
+
+ for &(_, ty) in self.argument_types() {
+ types.insert(ty);
+ }
+ }
+}
diff --git a/src/ir/int.rs b/src/ir/int.rs
new file mode 100644
index 00000000..89068e0f
--- /dev/null
+++ b/src/ir/int.rs
@@ -0,0 +1,113 @@
+//! Intermediate representation for integral types.
+
+/// Which integral type are we dealing with?
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum IntKind {
+ /// A `bool`.
+ Bool,
+
+ /// A `char`.
+ Char,
+
+ /// An `unsigned char`.
+ UChar,
+
+ /// A `short`.
+ Short,
+
+ /// An `unsigned short`.
+ UShort,
+
+ /// An `int`.
+ Int,
+
+ /// An `unsigned int`.
+ UInt,
+
+ /// A `long`.
+ Long,
+
+ /// An `unsigned long`.
+ ULong,
+
+ /// A `long long`.
+ LongLong,
+
+ /// An `unsigned long long`.
+ ULongLong,
+
+ /// A 8-bit signed integer.
+ I8,
+
+ /// A 8-bit unsigned integer.
+ U8,
+
+ /// A 16-bit signed integer.
+ I16,
+
+ /// Either a `char16_t` or a `wchar_t`.
+ U16,
+
+ /// A 32-bit signed integer.
+ I32,
+
+ /// A 32-bit unsigned integer.
+ U32,
+
+ /// A 64-bit signed integer.
+ I64,
+
+ /// A 64-bit unsigned integer.
+ U64,
+
+ /// An `int128_t`
+ I128,
+
+ /// A `uint128_t`.
+ U128,
+
+ /// A custom integer type, used to allow custom macro types depending on
+ /// range.
+ Custom {
+ /// The name of the type, which would be used without modification.
+ name: &'static str,
+ /// Whether the type is signed or not.
+ is_signed: bool,
+ },
+}
+
+impl IntKind {
+ /// Is this integral type signed?
+ pub fn is_signed(&self) -> bool {
+ use self::IntKind::*;
+ match *self {
+ Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
+ U32 | U64 | U128 => false,
+
+ Char | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
+ I128 => true,
+
+ Custom { is_signed, .. } => is_signed,
+ }
+ }
+
+ /// If this type has a known size, return it (in bytes). This is to
+ /// alleviate libclang sometimes not giving us a layout (like in the case
+ /// when an enum is defined inside a class with template parameters).
+ pub fn known_size(&self) -> Option<usize> {
+ use self::IntKind::*;
+ Some(match *self {
+ Bool | UChar | Char | U8 | I8 => 1,
+ U16 | I16 => 2,
+ U32 | I32 => 4,
+ U64 | I64 => 8,
+ I128 | U128 => 16,
+ _ => return None,
+ })
+ }
+
+ /// Whether this type's signedness matches the value.
+ pub fn signedness_matches(&self, val: i64) -> bool {
+ val >= 0 || self.is_signed()
+ }
+}
diff --git a/src/ir/item.rs b/src/ir/item.rs
new file mode 100644
index 00000000..df8fd222
--- /dev/null
+++ b/src/ir/item.rs
@@ -0,0 +1,1370 @@
+//! Bindgen's core intermediate representation type.
+
+use clang;
+use clang_sys;
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+use std::cell::{Cell, RefCell};
+use std::fmt::Write;
+use std::iter;
+use super::annotations::Annotations;
+use super::context::{BindgenContext, ItemId};
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::function::Function;
+use super::item_kind::ItemKind;
+use super::module::Module;
+use super::ty::{Type, TypeKind};
+use super::type_collector::{ItemSet, TypeCollector};
+
+/// A trait to get the canonical name from an item.
+///
+/// This is the trait that will eventually isolate all the logic related to name
+/// mangling and that kind of stuff.
+///
+/// This assumes no nested paths, at some point I'll have to make it a more
+/// complex thing.
+///
+/// This name is required to be safe for Rust, that is, is not expected to
+/// return any rust keyword from here.
+pub trait ItemCanonicalName {
+ /// Get the canonical name for this item.
+ fn canonical_name(&self, ctx: &BindgenContext) -> String;
+}
+
+/// The same, but specifies the path that needs to be followed to reach an item.
+///
+/// To contrast with canonical_name, here's an example:
+///
+/// ```c++
+/// namespace foo {
+/// const BAR = 3;
+/// }
+/// ```
+///
+/// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical
+/// name is just `"BAR"`.
+pub trait ItemCanonicalPath {
+ /// Get the namespace-aware canonical path for this item. This means that if
+ /// namespaces are disabled, you'll get a single item, and otherwise you get
+ /// the whole path.
+ fn namespace_aware_canonical_path(&self,
+ ctx: &BindgenContext)
+ -> Vec<String>;
+
+ /// Get the canonical path for this item.
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
+}
+
+/// A trait for iterating over an item and its parents and up its ancestor chain
+/// up to (but not including) the implicit root module.
+pub trait ItemAncestors {
+ /// Get an iterable over this item's ancestors.
+ fn ancestors<'a, 'b>(&self,
+ ctx: &'a BindgenContext<'b>)
+ -> ItemAncestorsIter<'a, 'b>;
+}
+
+cfg_if! {
+ if #[cfg(debug_assertions)] {
+ type DebugOnlyItemSet = ItemSet;
+ } else {
+ struct DebugOnlyItemSet;
+
+ impl DebugOnlyItemSet {
+ fn new() -> Self {
+ DebugOnlyItemSet
+ }
+
+ fn contains(&self,_id: &ItemId) -> bool {
+ false
+ }
+
+ fn insert(&mut self, _id: ItemId) {}
+ }
+ }
+}
+
+/// An iterator over an item and its ancestors.
+pub struct ItemAncestorsIter<'a, 'b>
+ where 'b: 'a,
+{
+ item: ItemId,
+ ctx: &'a BindgenContext<'b>,
+ seen: DebugOnlyItemSet,
+}
+
+impl<'a, 'b> ItemAncestorsIter<'a, 'b>
+ where 'b: 'a,
+{
+ fn new(ctx: &'a BindgenContext<'b>, item: ItemId) -> Self {
+ ItemAncestorsIter {
+ item: item,
+ ctx: ctx,
+ seen: DebugOnlyItemSet::new(),
+ }
+ }
+}
+
+impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
+ where 'b: 'a,
+{
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let item = self.ctx.resolve_item(self.item);
+
+ if item.parent_id() == self.item {
+ None
+ } else {
+ self.item = item.parent_id();
+
+ debug_assert!(!self.seen.contains(&item.id()));
+ self.seen.insert(item.id());
+
+ Some(item.id())
+ }
+ }
+}
+
+// Pure convenience
+impl ItemCanonicalName for ItemId {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).canonical_name(ctx)
+ }
+}
+
+impl ItemCanonicalPath for ItemId {
+ fn namespace_aware_canonical_path(&self,
+ ctx: &BindgenContext)
+ -> Vec<String> {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).namespace_aware_canonical_path(ctx)
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).canonical_path(ctx)
+ }
+}
+
+impl ItemAncestors for ItemId {
+ fn ancestors<'a, 'b>(&self,
+ ctx: &'a BindgenContext<'b>)
+ -> ItemAncestorsIter<'a, 'b> {
+ ItemAncestorsIter::new(ctx, *self)
+ }
+}
+
+impl ItemAncestors for Item {
+ fn ancestors<'a, 'b>(&self,
+ ctx: &'a BindgenContext<'b>)
+ -> ItemAncestorsIter<'a, 'b> {
+ self.id().ancestors(ctx)
+ }
+}
+
+impl TypeCollector for ItemId {
+ type Extra = ();
+
+ fn collect_types(&self,
+ ctx: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &()) {
+ ctx.resolve_item(*self).collect_types(ctx, types, extra);
+ }
+}
+
+impl TypeCollector for Item {
+ type Extra = ();
+
+ fn collect_types(&self,
+ ctx: &BindgenContext,
+ types: &mut ItemSet,
+ _extra: &()) {
+ if self.is_hidden(ctx) || types.contains(&self.id()) {
+ return;
+ }
+
+ match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ // There are some types, like resolved type references, where we
+ // don't want to stop collecting types even though they may be
+ // opaque.
+ if ty.should_be_traced_unconditionally() || !self.is_opaque(ctx) {
+ ty.collect_types(ctx, types, self);
+ }
+ }
+ ItemKind::Function(ref fun) => {
+ // Just the same way, it has not real meaning for a function to
+ // be opaque, so we trace across it.
+ types.insert(fun.signature());
+ }
+ ItemKind::Var(ref var) => {
+ types.insert(var.ty());
+ }
+ _ => {} // FIXME.
+ }
+ }
+}
+
+impl CanDeriveDebug for Item {
+ type Extra = ();
+
+ fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
+ match self.kind {
+ ItemKind::Type(ref ty) => {
+ if self.is_opaque(ctx) {
+ ty.layout(ctx)
+ .map_or(true, |l| l.opaque().can_derive_debug(ctx, ()))
+ } else {
+ ty.can_derive_debug(ctx, ())
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for Item {
+ type Extra = ();
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
+ match self.kind {
+ ItemKind::Type(ref ty) => {
+ if self.is_opaque(ctx) {
+ ty.layout(ctx)
+ .map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
+ } else {
+ ty.can_derive_copy(ctx, self)
+ }
+ }
+ _ => false,
+ }
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ match self.kind {
+ ItemKind::Type(ref ty) => {
+ if self.is_opaque(ctx) {
+ ty.layout(ctx)
+ .map_or(true, |l| l.opaque().can_derive_copy_in_array(ctx, ()))
+ } else {
+ ty.can_derive_copy_in_array(ctx, self)
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+/// An item is the base of the bindgen representation, it can be either a
+/// module, a type, a function, or a variable (see `ItemKind` for more
+/// information).
+///
+/// Items refer to each other by `ItemId`. Every item has its parent's
+/// id. Depending on the kind of item this is, it may also refer to other items,
+/// such as a compound type item referring to other types. Collectively, these
+/// references form a graph.
+///
+/// The entry-point to this graph is the "root module": a meta-item used to hold
+/// all top-level items.
+///
+/// An item may have a comment, and annotations (see the `annotations` module).
+///
+/// Note that even though we parse all the types of annotations in comments, not
+/// all of them apply to every item. Those rules are described in the
+/// `annotations` module.
+#[derive(Debug)]
+pub struct Item {
+ /// This item's id.
+ id: ItemId,
+
+ /// The item's local id, unique only amongst its siblings. Only used for
+ /// anonymous items.
+ ///
+ /// Lazily initialized in local_id().
+ ///
+ /// Note that only structs, unions, and enums get a local type id. In any
+ /// case this is an implementation detail.
+ local_id: Cell<Option<usize>>,
+
+ /// The next local id to use for a child..
+ next_child_local_id: Cell<usize>,
+
+ /// A cached copy of the canonical name, as returned by `canonical_name`.
+ ///
+ /// This is a fairly used operation during codegen so this makes bindgen
+ /// considerably faster in those cases.
+ canonical_name_cache: RefCell<Option<String>>,
+
+ /// A doc comment over the item, if any.
+ comment: Option<String>,
+ /// Annotations extracted from the doc comment, or the default ones
+ /// otherwise.
+ annotations: Annotations,
+ /// An item's parent id. This will most likely be a class where this item
+ /// was declared, or a module, etc.
+ ///
+ /// All the items have a parent, except the root module, in which case the
+ /// parent id is its own id.
+ parent_id: ItemId,
+ /// The item kind.
+ kind: ItemKind,
+}
+
+impl Item {
+ /// Construct a new `Item`.
+ pub fn new(id: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ parent_id: ItemId,
+ kind: ItemKind)
+ -> Self {
+ debug_assert!(id != parent_id || kind.is_module());
+ Item {
+ id: id,
+ local_id: Cell::new(None),
+ next_child_local_id: Cell::new(1),
+ canonical_name_cache: RefCell::new(None),
+ parent_id: parent_id,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ kind: kind,
+ }
+ }
+
+ /// Get this `Item`'s identifier.
+ pub fn id(&self) -> ItemId {
+ self.id
+ }
+
+ /// Get this `Item`'s parent's identifier.
+ ///
+ /// For the root module, the parent's ID is its own ID.
+ pub fn parent_id(&self) -> ItemId {
+ self.parent_id
+ }
+
+ /// Set this item's parent id.
+ ///
+ /// This is only used so replacements get generated in the proper module.
+ pub fn set_parent_for_replacement(&mut self, id: ItemId) {
+ self.parent_id = id;
+ }
+
+ /// Get this `Item`'s comment, if it has any.
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ /// What kind of item is this?
+ pub fn kind(&self) -> &ItemKind {
+ &self.kind
+ }
+
+ /// Get a mutable reference to this item's kind.
+ pub fn kind_mut(&mut self) -> &mut ItemKind {
+ &mut self.kind
+ }
+
+ /// Get an identifier that differentiates this item from its siblings.
+ ///
+ /// This should stay relatively stable in the face of code motion outside or
+ /// below this item's lexical scope, meaning that this can be useful for
+ /// generating relatively stable identifiers within a scope.
+ pub fn local_id(&self, ctx: &BindgenContext) -> usize {
+ if self.local_id.get().is_none() {
+ let parent = ctx.resolve_item(self.parent_id);
+ let local_id = parent.next_child_local_id.get();
+ parent.next_child_local_id.set(local_id + 1);
+ self.local_id.set(Some(local_id));
+ }
+ self.local_id.get().unwrap()
+ }
+
+ /// Returns whether this item is a top-level item, from the point of view of
+ /// bindgen.
+ ///
+ /// This point of view changes depending on whether namespaces are enabled
+ /// or not. That way, in the following example:
+ ///
+ /// ```c++
+ /// namespace foo {
+ /// static int var;
+ /// }
+ /// ```
+ ///
+ /// `var` would be a toplevel item if namespaces are disabled, but won't if
+ /// they aren't.
+ ///
+ /// This function is used to determine when the codegen phase should call
+ /// `codegen` on an item, since any item that is not top-level will be
+ /// generated by its parent.
+ pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
+ // FIXME: Workaround for some types falling behind when parsing weird
+ // stl classes, for example.
+ if ctx.options().enable_cxx_namespaces && self.kind().is_module() &&
+ self.id() != ctx.root_module() {
+ return false;
+ }
+
+ let mut parent = self.parent_id;
+ loop {
+ let parent_item = match ctx.resolve_item_fallible(parent) {
+ Some(item) => item,
+ None => return false,
+ };
+
+ if parent_item.id() == ctx.root_module() {
+ return true;
+ } else if ctx.options().enable_cxx_namespaces ||
+ !parent_item.kind().is_module() {
+ return false;
+ }
+
+ parent = parent_item.parent_id();
+ }
+ }
+
+ /// Get a reference to this item's underlying `Type`. Panic if this is some
+ /// other kind of item.
+ pub fn expect_type(&self) -> &Type {
+ self.kind().expect_type()
+ }
+
+ /// Get a reference to this item's underlying `Type`, or `None` if this is
+ /// some other kind of item.
+ pub fn as_type(&self) -> Option<&Type> {
+ self.kind().as_type()
+ }
+
+ /// Get a reference to this item's underlying `Function`. Panic if this is
+ /// some other kind of item.
+ pub fn expect_function(&self) -> &Function {
+ self.kind().expect_function()
+ }
+
+ /// Checks whether an item contains in its "type signature" some named type.
+ ///
+ /// This function is used to avoid unused template parameter errors in Rust
+ /// when generating typedef declarations, and also to know whether we need
+ /// to generate a `PhantomData` member for a template parameter.
+ ///
+ /// For example, in code like the following:
+ ///
+ /// ```c++
+ /// template<typename T, typename U>
+ /// struct Foo {
+ /// T bar;
+ ///
+ /// struct Baz {
+ /// U bas;
+ /// };
+ /// };
+ /// ```
+ ///
+ /// Both `Foo` and `Baz` contain both `T` and `U` template parameters in
+ /// their signature:
+ ///
+ /// * `Foo<T, U>`
+ /// * `Bar<T, U>`
+ ///
+ /// But the Rust structure for `Foo` would look like:
+ ///
+ /// ```rust
+ /// struct Foo<T, U> {
+ /// bar: T,
+ /// _phantom0: ::std::marker::PhantomData<U>,
+ /// }
+ /// ```
+ ///
+ /// because none of its member fields contained the `U` type in the
+ /// signature. Similarly, `Bar` would contain a `PhantomData<T>` type, for
+ /// the same reason.
+ ///
+ /// Note that this is somewhat similar to `applicable_template_args`, but
+ /// this also takes into account other kind of types, like arrays,
+ /// (`[T; 40]`), pointers: `*mut T`, etc...
+ ///
+ /// Normally we could do this check just in the `Type` kind, but we also
+ /// need to check the `applicable_template_args` more generally, since we
+ /// could need a type transitively from our parent, see the test added in
+ /// commit 2a3f93074dd2898669dbbce6e97e5cc4405d7cb1.
+ ///
+ /// It's kind of unfortunate (in the sense that it's a sort of complex
+ /// process), but I think it should get all the cases.
+ fn signature_contains_named_type(&self,
+ ctx: &BindgenContext,
+ ty: &Type)
+ -> bool {
+ debug_assert!(ty.is_named());
+ self.expect_type().signature_contains_named_type(ctx, ty) ||
+ self.applicable_template_args(ctx).iter().any(|template| {
+ ctx.resolve_type(*template).signature_contains_named_type(ctx, ty)
+ })
+ }
+
+ /// Returns the template arguments that apply to a struct. This is a concept
+ /// needed because of type declarations inside templates, for example:
+ ///
+ /// ```c++
+ /// template<typename T>
+ /// class Foo {
+ /// typedef T element_type;
+ /// typedef int Bar;
+ ///
+ /// template<typename U>
+ /// class Baz {
+ /// };
+ /// };
+ /// ```
+ ///
+ /// In this case, the applicable template arguments for the different types
+ /// would be:
+ ///
+ /// * `Foo`: [`T`]
+ /// * `Foo::element_type`: [`T`]
+ /// * `Foo::Bar`: [`T`]
+ /// * `Foo::Baz`: [`T`, `U`]
+ ///
+ /// You might notice that we can't generate something like:
+ ///
+ /// ```rust,ignore
+ /// type Foo_Bar<T> = ::std::os::raw::c_int;
+ /// ```
+ ///
+ /// since that would be invalid Rust. Still, conceptually, `Bar` *could* use
+ /// the template parameter type `T`, and that's exactly what this method
+ /// represents. The unused template parameters get stripped in the
+ /// `signature_contains_named_type` check.
+ pub fn applicable_template_args(&self,
+ ctx: &BindgenContext)
+ -> Vec<ItemId> {
+ let ty = match *self.kind() {
+ ItemKind::Type(ref ty) => ty,
+ _ => return vec![],
+ };
+
+ fn parent_contains(ctx: &BindgenContext,
+ parent_template_args: &[ItemId],
+ item: ItemId)
+ -> bool {
+ let item_ty = ctx.resolve_type(item);
+ parent_template_args.iter().any(|parent_item| {
+ let parent_ty = ctx.resolve_type(*parent_item);
+ match (parent_ty.kind(), item_ty.kind()) {
+ (&TypeKind::Named(ref n), &TypeKind::Named(ref i)) => {
+ n == i
+ }
+ _ => false,
+ }
+ })
+ }
+
+ match *ty.kind() {
+ TypeKind::Named(..) => vec![self.id()],
+ TypeKind::Array(inner, _) |
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_item(inner).applicable_template_args(ctx)
+ }
+ TypeKind::Alias(_, inner) => {
+ let parent_args = ctx.resolve_item(self.parent_id())
+ .applicable_template_args(ctx);
+ let inner = ctx.resolve_item(inner);
+
+ // Avoid unused type parameters, sigh.
+ parent_args.iter()
+ .cloned()
+ .filter(|arg| {
+ let arg = ctx.resolve_type(*arg);
+ arg.is_named() &&
+ inner.signature_contains_named_type(ctx, arg)
+ })
+ .collect()
+ }
+ // XXX Is this completely correct? Partial template specialization
+ // is hard anyways, sigh...
+ TypeKind::TemplateAlias(_, _, ref args) |
+ TypeKind::TemplateRef(_, ref args) => args.clone(),
+ // In a template specialization we've got all we want.
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ ci.template_args().iter().cloned().collect()
+ }
+ TypeKind::Comp(ref ci) => {
+ let mut parent_template_args =
+ ctx.resolve_item(self.parent_id())
+ .applicable_template_args(ctx);
+
+ for ty in ci.template_args() {
+ if !parent_contains(ctx, &parent_template_args, *ty) {
+ parent_template_args.push(*ty);
+ }
+ }
+
+ parent_template_args
+ }
+ _ => vec![],
+ }
+ }
+
+ /// Is this item a module?
+ pub fn is_module(&self) -> bool {
+ match self.kind {
+ ItemKind::Module(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Get this item's annotations.
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ /// Whether this item should be hidden.
+ ///
+ /// This may be due to either annotations or to other kind of configuration.
+ pub fn is_hidden(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.annotations.hide() ||
+ ctx.hidden_by_name(&self.canonical_path(ctx), self.id)
+ }
+
+ /// Is this item opaque?
+ pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.annotations.opaque() ||
+ ctx.opaque_by_name(&self.canonical_path(ctx))
+ }
+
+ /// Is this a reference to another type?
+ pub fn is_type_ref(&self) -> bool {
+ self.as_type().map_or(false, |ty| ty.is_type_ref())
+ }
+
+ /// Is this item a var type?
+ pub fn is_var(&self) -> bool {
+ match *self.kind() {
+ ItemKind::Var(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Take out item NameOptions
+ pub fn name<'item, 'ctx>(&'item self,
+ ctx: &'item BindgenContext<'ctx>)
+ -> NameOptions<'item, 'ctx> {
+ NameOptions::new(self, ctx)
+ }
+
+ /// Get the target item id for name generation.
+ fn name_target(&self, ctx: &BindgenContext) -> ItemId {
+ let mut targets_seen = DebugOnlyItemSet::new();
+ let mut item = self;
+
+ loop {
+ debug_assert!(!targets_seen.contains(&item.id()));
+ targets_seen.insert(item.id());
+
+ if self.annotations().use_instead_of().is_some() {
+ return self.id();
+ }
+
+ match *item.kind() {
+ ItemKind::Type(ref ty) => {
+ match *ty.kind() {
+ // If we're a template specialization, our name is our
+ // parent's name.
+ TypeKind::Comp(ref ci)
+ if ci.is_template_specialization() => {
+ let specialized =
+ ci.specialized_template().unwrap();
+ item = ctx.resolve_item(specialized);
+ }
+ // Same as above.
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::TemplateRef(inner, _) => {
+ item = ctx.resolve_item(inner);
+ }
+ _ => return item.id(),
+ }
+ }
+ _ => return item.id(),
+ }
+ }
+ }
+
+ /// Get this function item's name, or `None` if this item is not a function.
+ fn func_name(&self) -> Option<&str> {
+ match *self.kind() {
+ ItemKind::Function(ref func) => Some(func.name()),
+ _ => None,
+ }
+ }
+
+ /// Get the overload index for this method. If this is not a method, return
+ /// `None`.
+ fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
+ self.func_name().and_then(|func_name| {
+ let parent = ctx.resolve_item(self.parent_id());
+ if let ItemKind::Type(ref ty) = *parent.kind() {
+ if let TypeKind::Comp(ref ci) = *ty.kind() {
+ // All the constructors have the same name, so no need to
+ // resolve and check.
+ return ci.constructors()
+ .iter()
+ .position(|c| *c == self.id())
+ .or_else(|| {
+ ci.methods()
+ .iter()
+ .filter(|m| {
+ let item = ctx.resolve_item(m.signature());
+ let func = item.expect_function();
+ func.name() == func_name
+ })
+ .position(|m| m.signature() == self.id())
+ });
+ }
+ }
+
+ None
+ })
+ }
+
+ /// Get this item's base name (aka non-namespaced name).
+ fn base_name(&self, ctx: &BindgenContext) -> String {
+ if let Some(path) = self.annotations().use_instead_of() {
+ return path.last().unwrap().clone();
+ }
+
+ match *self.kind() {
+ ItemKind::Var(ref var) => var.name().to_owned(),
+ ItemKind::Module(ref module) => {
+ module.name()
+ .map(ToOwned::to_owned)
+ .unwrap_or_else(|| {
+ format!("_bindgen_mod_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Type(ref ty) => {
+ let name = match *ty.kind() {
+ TypeKind::ResolvedTypeRef(..) => {
+ panic!("should have resolved this in name_target()")
+ }
+ _ => ty.name(),
+ };
+ name.map(ToOwned::to_owned)
+ .unwrap_or_else(|| {
+ format!("_bindgen_ty_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Function(ref fun) => {
+ let mut name = fun.name().to_owned();
+
+ if let Some(idx) = self.overload_index(ctx) {
+ if idx > 0 {
+ write!(&mut name, "{}", idx).unwrap();
+ }
+ }
+
+ name
+ }
+ }
+ }
+
+ /// Get the canonical name without taking into account the replaces
+ /// annotation.
+ ///
+ /// This is the base logic used to implement hiding and replacing via
+ /// annotations, and also to implement proper name mangling.
+ ///
+ /// The idea is that each generated type in the same "level" (read: module
+ /// or namespace) has a unique canonical name.
+ ///
+ /// This name should be derived from the immutable state contained in the
+ /// type and the parent chain, since it should be consistent.
+ pub fn real_canonical_name(&self,
+ ctx: &BindgenContext,
+ opt: &NameOptions)
+ -> String {
+ let target = ctx.resolve_item(self.name_target(ctx));
+
+ // Short-circuit if the target has an override, and just use that.
+ if let Some(path) = target.annotations.use_instead_of() {
+ if ctx.options().enable_cxx_namespaces {
+ return path.last().unwrap().clone();
+ }
+ return path.join("_").to_owned();
+ }
+
+ let base_name = target.base_name(ctx);
+
+ // Named template type arguments are never namespaced, and never
+ // mangled.
+ if target.as_type().map_or(false, |ty| ty.is_named()) {
+ return base_name;
+ }
+
+ // Concatenate this item's ancestors' names together.
+ let mut names: Vec<_> = target.parent_id()
+ .ancestors(ctx)
+ .filter(|id| *id != ctx.root_module())
+ .take_while(|id| {
+ // Stop iterating ancestors once we reach a namespace.
+ !opt.within_namespaces || !ctx.resolve_item(*id).is_module()
+ })
+ .map(|id| {
+ let item = ctx.resolve_item(id);
+ let target = ctx.resolve_item(item.name_target(ctx));
+ target.base_name(ctx)
+ })
+ .filter(|name| !name.is_empty())
+ .collect();
+
+ names.reverse();
+
+ if !base_name.is_empty() {
+ names.push(base_name);
+ }
+
+ let name = names.join("_");
+
+ ctx.rust_mangle(&name).into_owned()
+ }
+
+ fn exposed_id(&self, ctx: &BindgenContext) -> String {
+ // Only use local ids for enums, classes, structs and union types. All
+ // other items use their global id.
+ let ty_kind = self.kind().as_type().map(|t| t.kind());
+ if let Some(ty_kind) = ty_kind {
+ match *ty_kind {
+ TypeKind::Comp(..) |
+ TypeKind::Enum(..) => return self.local_id(ctx).to_string(),
+ _ => {}
+ }
+ }
+
+ // Note that this `id_` prefix prevents (really unlikely) collisions
+ // between the global id and the local id of an item with the same
+ // parent.
+ format!("id_{}", self.id().as_usize())
+ }
+
+ /// Get a reference to this item's `Module`, or `None` if this is not a
+ /// `Module` item.
+ pub fn as_module(&self) -> Option<&Module> {
+ match self.kind {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Get a mutable reference to this item's `Module`, or `None` if this is
+ /// not a `Module` item.
+ pub fn as_module_mut(&mut self) -> Option<&mut Module> {
+ match self.kind {
+ ItemKind::Module(ref mut module) => Some(module),
+ _ => None,
+ }
+ }
+}
+
+// An utility function to handle recursing inside nested types.
+fn visit_child(cur: clang::Cursor,
+ id: ItemId,
+ ty: &clang::Type,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ result: &mut Result<ItemId, ParseError>)
+ -> clang_sys::CXChildVisitResult {
+ use clang_sys::*;
+ if result.is_ok() {
+ return CXChildVisit_Break;
+ }
+
+ *result = Item::from_ty_with_id(id, ty, Some(cur), parent_id, ctx);
+
+ match *result {
+ Ok(..) => CXChildVisit_Break,
+ Err(ParseError::Recurse) => {
+ cur.visit(|c| visit_child(c, id, ty, parent_id, ctx, result));
+ CXChildVisit_Continue
+ }
+ Err(ParseError::Continue) => CXChildVisit_Continue,
+ }
+}
+
+impl ClangItemParser for Item {
+ fn builtin_type(kind: TypeKind,
+ is_const: bool,
+ ctx: &mut BindgenContext)
+ -> ItemId {
+ // Feel free to add more here, I'm just lazy.
+ match kind {
+ TypeKind::Void |
+ TypeKind::Int(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Float(..) => {}
+ _ => panic!("Unsupported builtin type"),
+ }
+
+ let ty = Type::new(None, None, kind, is_const);
+ let id = ctx.next_item_id();
+ let module = ctx.root_module();
+ ctx.add_item(Item::new(id, None, None, module, ItemKind::Type(ty)),
+ None,
+ None);
+ id
+ }
+
+
+ fn parse(cursor: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ItemId, ParseError> {
+ use ir::function::Function;
+ use ir::module::Module;
+ use ir::var::Var;
+ use clang_sys::*;
+
+ if !cursor.is_valid() {
+ return Err(ParseError::Continue);
+ }
+
+ let comment = cursor.raw_comment();
+ let annotations = Annotations::new(&cursor);
+
+ let current_module = ctx.current_module();
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+
+ macro_rules! try_parse {
+ ($what:ident) => {
+ match $what::parse(cursor, ctx) {
+ Ok(ParseResult::New(item, declaration)) => {
+ let id = ctx.next_item_id();
+
+ ctx.add_item(Item::new(id, comment, annotations,
+ relevant_parent_id,
+ ItemKind::$what(item)),
+ declaration,
+ Some(cursor));
+ return Ok(id);
+ }
+ Ok(ParseResult::AlreadyResolved(id)) => {
+ return Ok(id);
+ }
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {},
+ }
+ }
+ }
+
+ try_parse!(Module);
+
+ // NOTE: Is extremely important to parse functions and vars **before**
+ // types. Otherwise we can parse a function declaration as a type
+ // (which is legal), and lose functions to generate.
+ //
+ // In general, I'm not totally confident this split between
+ // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but
+ // I guess we can try.
+ try_parse!(Function);
+ try_parse!(Var);
+
+ // Types are sort of special, so to avoid parsing template classes
+ // twice, handle them separately.
+ {
+ let applicable_cursor = cursor.definition().unwrap_or(cursor);
+ match Self::from_ty(&applicable_cursor.cur_type(),
+ Some(applicable_cursor),
+ parent_id,
+ ctx) {
+ Ok(ty) => return Ok(ty),
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {}
+ }
+ }
+
+ // Guess how does clang treat extern "C" blocks?
+ if cursor.kind() == CXCursor_UnexposedDecl {
+ Err(ParseError::Recurse)
+ } else {
+ // We whitelist cursors here known to be unhandled, to prevent being
+ // too noisy about this.
+ match cursor.kind() {
+ CXCursor_MacroDefinition |
+ CXCursor_MacroExpansion |
+ CXCursor_UsingDeclaration |
+ CXCursor_UsingDirective |
+ CXCursor_StaticAssert |
+ CXCursor_InclusionDirective => {
+ debug!("Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor);
+ }
+ _ => {
+ // ignore toplevel operator overloads
+ let spelling = cursor.spelling();
+ if !spelling.starts_with("operator") {
+ error!("Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor);
+ }
+ }
+ }
+
+ Err(ParseError::Continue)
+ }
+ }
+
+ fn from_ty_or_ref(ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> ItemId {
+ let id = ctx.next_item_id();
+ Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// Parse a C++ type. If we find a reference to a type that has not been
+ /// defined yet, use `UnresolvedTypeRef` as a placeholder.
+ ///
+ /// This logic is needed to avoid parsing items with the incorrect parent
+ /// and it's sort of complex to explain, so I'll just point to
+ /// `tests/headers/typeref.hpp` to see the kind of constructs that forced
+ /// this.
+ ///
+ /// Typerefs are resolved once parsing is completely done, see
+ /// `BindgenContext::resolve_typerefs`.
+ fn from_ty_or_ref_with_id(potential_id: ItemId,
+ ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> ItemId {
+ debug!("from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}",
+ potential_id,
+ ty,
+ location,
+ parent_id);
+
+ if ctx.collected_typerefs() {
+ debug!("refs already collected, resolving directly");
+ return Self::from_ty_with_id(potential_id,
+ &ty,
+ location,
+ parent_id,
+ ctx)
+ .expect("Unable to resolve type");
+ }
+
+ if let Some(ty) =
+ ctx.builtin_or_resolved_ty(potential_id, parent_id, &ty, location) {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return ty;
+ }
+
+ debug!("New unresolved type reference: {:?}, {:?}", ty, location);
+
+ let is_const = ty.is_const();
+ let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id);
+ let current_module = ctx.current_module();
+ ctx.add_item(Item::new(potential_id,
+ None,
+ None,
+ parent_id.unwrap_or(current_module),
+ ItemKind::Type(Type::new(None,
+ None,
+ kind,
+ is_const))),
+ Some(clang::Cursor::null()),
+ None);
+ potential_id
+ }
+
+
+ fn from_ty(ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ItemId, ParseError> {
+ let id = ctx.next_item_id();
+ Self::from_ty_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// This is one of the trickiest methods you'll find (probably along with
+ /// some of the ones that handle templates in `BindgenContext`).
+ ///
+ /// This method parses a type, given the potential id of that type (if
+ /// parsing it was correct), an optional location we're scanning, which is
+ /// critical some times to obtain information, an optional parent item id,
+ /// that will, if it's `None`, become the current module id, and the
+ /// context.
+ fn from_ty_with_id(id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ItemId, ParseError> {
+ use clang_sys::*;
+
+ let decl = {
+ let decl = ty.declaration();
+ decl.definition().unwrap_or(decl)
+ };
+
+ let comment = decl.raw_comment()
+ .or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
+ let annotations = Annotations::new(&decl)
+ .or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
+
+ if let Some(ref annotations) = annotations {
+ if let Some(ref replaced) = annotations.use_instead_of() {
+ ctx.replace(replaced, id);
+ }
+ }
+
+ if let Some(ty) =
+ ctx.builtin_or_resolved_ty(id, parent_id, ty, location) {
+ return Ok(ty);
+ }
+
+ // First, check we're not recursing.
+ let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
+ let declaration_to_look_for = if valid_decl {
+ decl.canonical()
+ } else if location.is_some() &&
+ location.unwrap().kind() ==
+ CXCursor_ClassTemplate {
+ valid_decl = true;
+ location.unwrap()
+ } else {
+ decl
+ };
+
+ if valid_decl {
+ if let Some(&(_, item_id)) = ctx.currently_parsed_types
+ .iter()
+ .find(|&&(d, _)| d == declaration_to_look_for) {
+ debug!("Avoiding recursion parsing type: {:?}", ty);
+ return Ok(item_id);
+ }
+ }
+
+ let current_module = ctx.current_module();
+ if valid_decl {
+ ctx.currently_parsed_types.push((declaration_to_look_for, id));
+ }
+
+ let result = Type::from_clang_ty(id, ty, location, parent_id, ctx);
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+ let ret = match result {
+ Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty),
+ Ok(ParseResult::New(item, declaration)) => {
+ ctx.add_item(Item::new(id,
+ comment,
+ annotations,
+ relevant_parent_id,
+ ItemKind::Type(item)),
+ declaration,
+ location);
+ Ok(id)
+ }
+ Err(ParseError::Continue) => Err(ParseError::Continue),
+ Err(ParseError::Recurse) => {
+ debug!("Item::from_ty recursing in the ast");
+ let mut result = Err(ParseError::Recurse);
+ if let Some(ref location) = location {
+ // Need to pop here, otherwise we'll get stuck.
+ //
+ // TODO: Find a nicer interface, really. Also, the
+ // declaration_to_look_for suspiciously shares a lot of
+ // logic with ir::context, so we should refactor that.
+ if valid_decl {
+ let (popped_decl, _) =
+ ctx.currently_parsed_types.pop().unwrap();
+ assert_eq!(popped_decl, declaration_to_look_for);
+ }
+
+ location.visit(|cur| {
+ visit_child(cur, id, ty, parent_id, ctx, &mut result)
+ });
+
+ if valid_decl {
+ ctx.currently_parsed_types
+ .push((declaration_to_look_for, id));
+ }
+ }
+ // If we have recursed into the AST all we know, and we still
+ // haven't found what we've got, let's just make a named type.
+ //
+ // This is what happens with some template members, for example.
+ //
+ // FIXME: Maybe we should restrict this to things with parent?
+ // It's harmless, but if we restrict that, then
+ // tests/headers/nsStyleAutoArray.hpp crashes.
+ if let Err(ParseError::Recurse) = result {
+ warn!("Unknown type, assuming named template type: \
+ id = {:?}; spelling = {}",
+ id,
+ ty.spelling());
+ Ok(Self::named_type_with_id(id,
+ ty.spelling(),
+ relevant_parent_id,
+ ctx))
+ } else {
+ result
+ }
+ }
+ };
+
+ if valid_decl {
+ let (popped_decl, _) = ctx.currently_parsed_types.pop().unwrap();
+ assert_eq!(popped_decl, declaration_to_look_for);
+ }
+
+ ret
+ }
+
+ /// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
+ /// always local so it's the only exception when there's no declaration for
+ /// a type.
+ ///
+ /// It must have an id, and must not be the current module id. Ideally we
+ /// could assert the parent id is a Comp(..) type, but that info isn't
+ /// available yet.
+ fn named_type_with_id<S>(id: ItemId,
+ name: S,
+ parent_id: ItemId,
+ ctx: &mut BindgenContext)
+ -> ItemId
+ where S: Into<String>,
+ {
+ // see tests/headers/const_tparam.hpp
+ // and tests/headers/variadic_tname.hpp
+ let name = name.into().replace("const ", "").replace(".", "");
+
+ ctx.add_item(Item::new(id,
+ None,
+ None,
+ parent_id,
+ ItemKind::Type(Type::named(name))),
+ None,
+ None);
+
+ id
+ }
+
+ fn named_type<S>(name: S,
+ parent_id: ItemId,
+ ctx: &mut BindgenContext)
+ -> ItemId
+ where S: Into<String>,
+ {
+ let id = ctx.next_item_id();
+ Self::named_type_with_id(id, name, parent_id, ctx)
+ }
+}
+
+impl ItemCanonicalName for Item {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ if self.canonical_name_cache.borrow().is_none() {
+ let in_namespace = ctx.options().enable_cxx_namespaces ||
+ ctx.options().disable_name_namespacing;
+
+ *self.canonical_name_cache.borrow_mut() = if in_namespace {
+ Some(self.name(ctx).within_namespaces().get())
+ } else {
+ Some(self.name(ctx).get())
+ };
+ }
+ return self.canonical_name_cache.borrow().as_ref().unwrap().clone();
+ }
+}
+
+impl ItemCanonicalPath for Item {
+ fn namespace_aware_canonical_path(&self,
+ ctx: &BindgenContext)
+ -> Vec<String> {
+ let path = self.canonical_path(ctx);
+ if ctx.options().enable_cxx_namespaces {
+ return path;
+ }
+ if ctx.options().disable_name_namespacing {
+ return vec![path.last().unwrap().clone()];
+ }
+ return vec![path[1..].join("_")];
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ if let Some(path) = self.annotations().use_instead_of() {
+ let mut ret =
+ vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()];
+ ret.extend_from_slice(path);
+ return ret;
+ }
+
+ let target = ctx.resolve_item(self.name_target(ctx));
+ let mut path: Vec<_> = target.ancestors(ctx)
+ .chain(iter::once(ctx.root_module()))
+ .map(|id| ctx.resolve_item(id))
+ .filter(|item| {
+ item.id() == target.id() ||
+ item.as_module().map_or(false, |module| {
+ !module.is_inline() ||
+ ctx.options().conservative_inline_namespaces
+ })
+ })
+ .map(|item| {
+ ctx.resolve_item(item.name_target(ctx))
+ .name(ctx)
+ .within_namespaces()
+ .get()
+ })
+ .collect();
+ path.reverse();
+ path
+ }
+}
+
+/// Builder struct for naming variations, which hold inside different
+/// flags for naming options.
+#[derive(Debug)]
+pub struct NameOptions<'item, 'ctx>
+ where 'ctx: 'item,
+{
+ item: &'item Item,
+ ctx: &'item BindgenContext<'ctx>,
+ within_namespaces: bool,
+}
+
+impl<'item, 'ctx> NameOptions<'item, 'ctx> {
+ /// Construct a new `NameOptions`
+ pub fn new(item: &'item Item, ctx: &'item BindgenContext<'ctx>) -> Self {
+ NameOptions {
+ item: item,
+ ctx: ctx,
+ within_namespaces: false,
+ }
+ }
+
+ /// Construct the name without the item's containing C++ namespaces mangled
+ /// into it. In other words, the item's name within the item's namespace.
+ pub fn within_namespaces(&mut self) -> &mut Self {
+ self.within_namespaces = true;
+ self
+ }
+
+ /// Construct a name `String`
+ pub fn get(&self) -> String {
+ self.item.real_canonical_name(self.ctx, self)
+ }
+}
diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs
new file mode 100644
index 00000000..d9e4690c
--- /dev/null
+++ b/src/ir/item_kind.rs
@@ -0,0 +1,114 @@
+//! Different variants of an `Item` in our intermediate representation.
+
+use super::function::Function;
+use super::module::Module;
+use super::ty::Type;
+use super::var::Var;
+
+/// A item we parse and translate.
+#[derive(Debug)]
+pub enum ItemKind {
+ /// A module, created implicitly once (the root module), or via C++
+ /// namespaces.
+ Module(Module),
+
+ /// A type declared in any of the multiple ways it can be declared.
+ Type(Type),
+
+ /// A function or method declaration.
+ Function(Function),
+
+ /// A variable declaration, most likely a static.
+ Var(Var),
+}
+
+impl ItemKind {
+ /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it
+ /// is some other kind.
+ pub fn as_module(&self) -> Option<&Module> {
+ match *self {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Is this a module?
+ pub fn is_module(&self) -> bool {
+ self.as_module().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it
+ /// is some other kind.
+ pub fn expect_module(&self) -> &Module {
+ self.as_module().expect("Not a module")
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if
+ /// it is some other kind.
+ pub fn as_function(&self) -> Option<&Function> {
+ match *self {
+ ItemKind::Function(ref func) => Some(func),
+ _ => None,
+ }
+ }
+
+ /// Is this a function?
+ pub fn is_function(&self) -> bool {
+ self.as_function().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Function`, or panic if
+ /// it is some other kind.
+ pub fn expect_function(&self) -> &Function {
+ self.as_function().expect("Not a function")
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if
+ /// it is some other kind.
+ pub fn as_type(&self) -> Option<&Type> {
+ match *self {
+ ItemKind::Type(ref ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None`
+ /// if it is some other kind.
+ pub fn as_type_mut(&mut self) -> Option<&mut Type> {
+ match *self {
+ ItemKind::Type(ref mut ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Is this a type?
+ pub fn is_type(&self) -> bool {
+ self.as_type().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is
+ /// some other kind.
+ pub fn expect_type(&self) -> &Type {
+ self.as_type().expect("Not a type")
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is
+ /// some other kind.
+ pub fn as_var(&self) -> Option<&Var> {
+ match *self {
+ ItemKind::Var(ref v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// Is this a variable?
+ pub fn is_var(&self) -> bool {
+ self.as_var().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is
+ /// some other kind.
+ pub fn expect_var(&self) -> &Var {
+ self.as_var().expect("Not a var")
+ }
+}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
new file mode 100644
index 00000000..033fff62
--- /dev/null
+++ b/src/ir/layout.rs
@@ -0,0 +1,91 @@
+//! Intermediate representation for the physical layout of some type.
+
+use std::cmp;
+use super::context::BindgenContext;
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+
+/// A type that represents the struct layout of a type.
+#[derive(Debug, Clone, Copy)]
+pub struct Layout {
+ /// The size (in bytes) of this layout.
+ pub size: usize,
+ /// The alignment (in bytes) of this layout.
+ pub align: usize,
+ /// Whether this layout's members are packed or not.
+ pub packed: bool,
+}
+
+impl Layout {
+ /// Construct a new `Layout` with the given `size` and `align`. It is not
+ /// packed.
+ pub fn new(size: usize, align: usize) -> Self {
+ Layout {
+ size: size,
+ align: align,
+ packed: false,
+ }
+ }
+
+ /// Is this a zero-sized layout?
+ pub fn is_zero(&self) -> bool {
+ self.size == 0 && self.align == 0
+ }
+
+ /// Construct a zero-sized layout.
+ pub fn zero() -> Self {
+ Self::new(0, 0)
+ }
+
+ /// Get this layout as an opaque type.
+ pub fn opaque(&self) -> Opaque {
+ Opaque(*self)
+ }
+}
+
+/// When we are treating a type as opaque, it is just a blob with a `Layout`.
+pub struct Opaque(pub Layout);
+
+impl Opaque {
+ /// Return the known rust type we should use to create a correctly-aligned
+ /// field with this layout.
+ pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
+ Some(match self.0.align {
+ 8 => "u64",
+ 4 => "u32",
+ 2 => "u16",
+ 1 => "u8",
+ _ => return None,
+ })
+ }
+
+ /// Return the array size that an opaque type for this layout should have if
+ /// we know the correct type for it, or `None` otherwise.
+ pub fn array_size(&self) -> Option<usize> {
+ if self.known_rust_type_for_array().is_some() {
+ Some(self.0.size / cmp::max(self.0.align, 1))
+ } else {
+ None
+ }
+ }
+}
+
+impl CanDeriveDebug for Opaque {
+ type Extra = ();
+
+ fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool {
+ self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for Opaque {
+ type Extra = ();
+
+ fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool {
+ self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.can_derive_copy(ctx, ())
+ }
+}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
new file mode 100644
index 00000000..73793b16
--- /dev/null
+++ b/src/ir/mod.rs
@@ -0,0 +1,19 @@
+//! The ir module defines bindgen's intermediate representation.
+//!
+//! Parsing C/C++ generates the IR, while code generation outputs Rust code from
+//! the IR.
+
+pub mod annotations;
+pub mod comp;
+pub mod context;
+pub mod derive;
+pub mod enum_ty;
+pub mod function;
+pub mod int;
+pub mod item;
+pub mod item_kind;
+pub mod layout;
+pub mod module;
+pub mod ty;
+pub mod type_collector;
+pub mod var;
diff --git a/src/ir/module.rs b/src/ir/module.rs
new file mode 100644
index 00000000..002fe36e
--- /dev/null
+++ b/src/ir/module.rs
@@ -0,0 +1,78 @@
+//! Intermediate representation for modules (AKA C++ namespaces).
+
+use clang;
+use parse::{ClangSubItemParser, ParseError, ParseResult};
+use parse_one;
+use super::context::{BindgenContext, ItemId};
+
+/// Whether this module is inline or not.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ModuleKind {
+ /// This module is not inline.
+ Normal,
+ /// This module is inline, as in `inline namespace foo {}`.
+ Inline,
+}
+
+/// A module, as in, a C++ namespace.
+#[derive(Clone, Debug)]
+pub struct Module {
+ /// The name of the module, or none if it's anonymous.
+ name: Option<String>,
+ /// The kind of module this is.
+ kind: ModuleKind,
+ /// The children of this module, just here for convenience.
+ children_ids: Vec<ItemId>,
+}
+
+impl Module {
+ /// Construct a new `Module`.
+ pub fn new(name: Option<String>, kind: ModuleKind) -> Self {
+ Module {
+ name: name,
+ kind: kind,
+ children_ids: vec![],
+ }
+ }
+
+ /// Get this module's name.
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ /// Get a mutable reference to this module's children.
+ pub fn children_mut(&mut self) -> &mut Vec<ItemId> {
+ &mut self.children_ids
+ }
+
+ /// Get this module's children.
+ pub fn children(&self) -> &[ItemId] {
+ &self.children_ids
+ }
+
+ /// Whether this namespace is inline.
+ pub fn is_inline(&self) -> bool {
+ self.kind == ModuleKind::Inline
+ }
+}
+
+impl ClangSubItemParser for Module {
+ fn parse(cursor: clang::Cursor,
+ ctx: &mut BindgenContext)
+ -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ match cursor.kind() {
+ CXCursor_Namespace => {
+ let module_id = ctx.module(cursor);
+ ctx.with_module(module_id, |ctx| {
+ cursor.visit(|cursor| {
+ parse_one(ctx, cursor, Some(module_id))
+ })
+ });
+
+ Ok(ParseResult::AlreadyResolved(module_id))
+ }
+ _ => Err(ParseError::Continue),
+ }
+ }
+}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
new file mode 100644
index 00000000..c1ed5b64
--- /dev/null
+++ b/src/ir/ty.rs
@@ -0,0 +1,926 @@
+//! Everything related to types in our intermediate representation.
+
+use clang::{self, Cursor};
+use parse::{ClangItemParser, ParseError, ParseResult};
+use super::comp::CompInfo;
+use super::context::{BindgenContext, ItemId};
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::enum_ty::Enum;
+use super::function::FunctionSig;
+use super::int::IntKind;
+use super::item::Item;
+use super::layout::Layout;
+use super::type_collector::{ItemSet, TypeCollector};
+
+/// The base representation of a type in bindgen.
+///
+/// A type has an optional name, which if present cannot be empty, a `layout`
+/// (size, alignment and packedness) if known, a `Kind`, which determines which
+/// kind of type it is, and whether the type is const.
+#[derive(Debug)]
+pub struct Type {
+ /// The name of the type, or None if it was an unnamed struct or union.
+ name: Option<String>,
+ /// The layout of the type, if known.
+ layout: Option<Layout>,
+ /// The inner kind of the type
+ kind: TypeKind,
+ /// Whether this type is const-qualified.
+ is_const: bool,
+}
+
+/// The maximum number of items in an array for which Rust implements common
+/// traits, and so if we have a type containing an array with more than this
+/// many items, we won't be able to derive common traits on that type.
+///
+/// We need type-level integers yesterday :'(
+pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
+
+impl Type {
+ /// Get the underlying `CompInfo` for this type, or `None` if this is some
+ /// other kind of type.
+ pub fn as_comp(&self) -> Option<&CompInfo> {
+ match self.kind {
+ TypeKind::Comp(ref ci) => Some(ci),
+ _ => None,
+ }
+ }
+
+ /// Construct a new `Type`.
+ pub fn new(name: Option<String>,
+ layout: Option<Layout>,
+ kind: TypeKind,
+ is_const: bool)
+ -> Self {
+ Type {
+ name: name,
+ layout: layout,
+ kind: kind,
+ is_const: is_const,
+ }
+ }
+
+ /// Which kind of type is this?
+ pub fn kind(&self) -> &TypeKind {
+ &self.kind
+ }
+
+ /// Overrides the kind of the item. This is mostly a template alias
+ /// implementation detail, and debug assertions guard it like so.
+ pub fn set_kind(&mut self, kind: TypeKind) {
+ if cfg!(debug_assertions) {
+ match (&self.kind, &kind) {
+ (&TypeKind::Alias(ref alias_name, alias_inner),
+ &TypeKind::TemplateAlias(ref name, inner, _)) => {
+ assert_eq!(alias_name, name);
+ assert_eq!(alias_inner, inner);
+ }
+ _ => panic!("Unexpected kind in `set_kind`!"),
+ };
+ }
+ self.kind = kind;
+ }
+
+ /// Get a mutable reference to this type's kind.
+ pub fn kind_mut(&mut self) -> &mut TypeKind {
+ &mut self.kind
+ }
+
+ /// Get this type's name.
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|name| &**name)
+ }
+
+ /// Is this a compound type?
+ pub fn is_comp(&self) -> bool {
+ match self.kind {
+ TypeKind::Comp(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a named type?
+ pub fn is_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a template alias type?
+ pub fn is_template_alias(&self) -> bool {
+ match self.kind {
+ TypeKind::TemplateAlias(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a function type?
+ pub fn is_function(&self) -> bool {
+ match self.kind {
+ TypeKind::Function(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this an enum type?
+ pub fn is_enum(&self) -> bool {
+ match self.kind {
+ TypeKind::Enum(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this either a builtin or named type?
+ pub fn is_builtin_or_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Function(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::BlockPointer |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Creates a new named type, with name `name`.
+ pub fn named(name: String) -> Self {
+ assert!(!name.is_empty());
+ // TODO: stop duplicating the name, it's stupid.
+ let kind = TypeKind::Named(name.clone());
+ Self::new(Some(name), None, kind, false)
+ }
+
+ /// Is this a floating point type?
+ pub fn is_float(&self) -> bool {
+ match self.kind {
+ TypeKind::Float(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a boolean type?
+ pub fn is_bool(&self) -> bool {
+ match self.kind {
+ TypeKind::Int(IntKind::Bool) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this an integer type?
+ pub fn is_integer(&self) -> bool {
+ match self.kind {
+ TypeKind::Int(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a `const` qualified type?
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ /// Is this a reference to another type?
+ pub fn is_type_ref(&self) -> bool {
+ match self.kind {
+ TypeKind::ResolvedTypeRef(_) |
+ TypeKind::UnresolvedTypeRef(_, _, _) => true,
+ _ => false,
+ }
+ }
+
+ /// What is the layout of this type?
+ pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ use std::mem;
+
+ self.layout.or_else(|| {
+ match self.kind {
+ TypeKind::Comp(ref ci) => ci.layout(ctx),
+ // FIXME(emilio): This is a hack for anonymous union templates.
+ // Use the actual pointer size!
+ TypeKind::Pointer(..) |
+ TypeKind::BlockPointer => {
+ Some(Layout::new(mem::size_of::<*mut ()>(),
+ mem::align_of::<*mut ()>()))
+ }
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_type(inner).layout(ctx)
+ }
+ _ => None,
+ }
+ })
+ }
+
+ /// Whether this type has a vtable.
+ pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ // FIXME: Can we do something about template parameters? Huh...
+ match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::TemplateAlias(_, t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx),
+ TypeKind::Comp(ref info) => info.has_vtable(ctx),
+ _ => false,
+ }
+
+ }
+
+ /// Returns whether this type has a destructor.
+ pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
+ match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::TemplateAlias(_, t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) => {
+ ctx.resolve_type(t).has_destructor(ctx)
+ }
+ TypeKind::Comp(ref info) => info.has_destructor(ctx),
+ _ => false,
+ }
+ }
+
+ /// See the comment in `Item::signature_contains_named_type`.
+ pub fn signature_contains_named_type(&self,
+ ctx: &BindgenContext,
+ ty: &Type)
+ -> bool {
+ let name = match *ty.kind() {
+ TypeKind::Named(ref name) => name,
+ ref other @ _ => unreachable!("Not a named type: {:?}", other),
+ };
+
+ match self.kind {
+ TypeKind::Named(ref this_name) => this_name == name,
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) |
+ TypeKind::Pointer(t) |
+ TypeKind::Alias(_, t) => {
+ ctx.resolve_type(t)
+ .signature_contains_named_type(ctx, ty)
+ }
+ TypeKind::Function(ref sig) => {
+ sig.argument_types().iter().any(|&(_, arg)| {
+ ctx.resolve_type(arg)
+ .signature_contains_named_type(ctx, ty)
+ }) ||
+ ctx.resolve_type(sig.return_type())
+ .signature_contains_named_type(ctx, ty)
+ }
+ TypeKind::TemplateAlias(_, _, ref template_args) |
+ TypeKind::TemplateRef(_, ref template_args) => {
+ template_args.iter().any(|arg| {
+ ctx.resolve_type(*arg)
+ .signature_contains_named_type(ctx, ty)
+ })
+ }
+ TypeKind::Comp(ref ci) => ci.signature_contains_named_type(ctx, ty),
+ _ => false,
+ }
+ }
+
+ /// See safe_canonical_type.
+ pub fn canonical_type<'tr>(&'tr self,
+ ctx: &'tr BindgenContext)
+ -> &'tr Type {
+ self.safe_canonical_type(ctx)
+ .expect("Should have been resolved after parsing!")
+ }
+
+ /// Returns the canonical type of this type, that is, the "inner type".
+ ///
+ /// For example, for a `typedef`, the canonical type would be the
+ /// `typedef`ed type, for a template specialization, would be the template
+ /// its specializing, and so on. Return None if the type is unresolved.
+ pub fn safe_canonical_type<'tr>(&'tr self,
+ ctx: &'tr BindgenContext)
+ -> Option<&'tr Type> {
+ match self.kind {
+ TypeKind::Named(..) |
+ TypeKind::Array(..) |
+ TypeKind::Comp(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::BlockPointer |
+ TypeKind::Pointer(..) => Some(self),
+
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateAlias(_, inner, _) |
+ TypeKind::TemplateRef(inner, _) => {
+ ctx.resolve_type(inner).safe_canonical_type(ctx)
+ }
+
+ TypeKind::UnresolvedTypeRef(..) => None,
+ }
+ }
+
+ /// There are some types we don't want to stop at when finding an opaque
+ /// item, so we can arrive to the proper item that needs to be generated.
+ pub fn should_be_traced_unconditionally(&self) -> bool {
+ match self.kind {
+ TypeKind::Function(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TemplateRef(..) |
+ TypeKind::ResolvedTypeRef(..) => true,
+ _ => false,
+ }
+ }
+}
+
+impl CanDeriveDebug for Type {
+ type Extra = ();
+
+ fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
+ match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT && t.can_derive_debug(ctx, ())
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(_, t, _) |
+ TypeKind::Alias(_, t) => t.can_derive_debug(ctx, ()),
+ TypeKind::Comp(ref info) => {
+ info.can_derive_debug(ctx, self.layout(ctx))
+ }
+ _ => true,
+ }
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for Type {
+ type Extra = &'a Item;
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
+ t.can_derive_copy_in_array(ctx, ())
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(_, t, _) |
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) => t.can_derive_copy(ctx, ()),
+ TypeKind::Comp(ref info) => {
+ info.can_derive_copy(ctx, (item, self.layout(ctx)))
+ }
+ _ => true,
+ }
+ }
+
+ fn can_derive_copy_in_array(&self,
+ ctx: &BindgenContext,
+ item: &Item)
+ -> bool {
+ match self.kind {
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(_, t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::Array(t, _) => t.can_derive_copy_in_array(ctx, ()),
+ TypeKind::Named(..) => false,
+ _ => self.can_derive_copy(ctx, item),
+ }
+ }
+}
+
+/// The kind of float this type represents.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum FloatKind {
+ /// A `float`.
+ Float,
+ /// A `double`.
+ Double,
+ /// A `long double`.
+ LongDouble,
+ /// A `__float128`.
+ Float128,
+}
+
+/// The different kinds of types that we can parse.
+#[derive(Debug)]
+pub enum TypeKind {
+ /// The void type.
+ Void,
+
+ /// The `nullptr_t` type.
+ NullPtr,
+
+ /// A compound type, that is, a class, struct, or union.
+ Comp(CompInfo),
+
+ /// An integer type, of a given kind. `bool` and `char` are also considered
+ /// integers.
+ Int(IntKind),
+
+ /// A floating point type.
+ Float(FloatKind),
+
+ /// A complex floating point type.
+ Complex(FloatKind),
+
+ /// A type alias, with a name, that points to another type.
+ Alias(String, ItemId),
+
+ /// A templated alias, pointing to an inner type, just as `Alias`, but with
+ /// template parameters.
+ TemplateAlias(String, ItemId, Vec<ItemId>),
+
+ /// An array of a type and a lenght.
+ Array(ItemId, usize),
+
+ /// A function type, with a given signature.
+ Function(FunctionSig),
+
+ /// An `enum` type.
+ Enum(Enum),
+
+ /// A pointer to a type. The bool field represents whether it's const or
+ /// not.
+ Pointer(ItemId),
+
+ /// A pointer to an Apple block.
+ BlockPointer,
+
+ /// A reference to a type, as in: int& foo().
+ Reference(ItemId),
+
+ /// A reference to a template, with different template parameter names. To
+ /// see why this is needed, check out the creation of this variant in
+ /// `Type::from_clang_ty`.
+ TemplateRef(ItemId, Vec<ItemId>),
+
+ /// A reference to a yet-to-resolve type. This stores the clang cursor
+ /// itself, and postpones its resolution.
+ ///
+ /// These are gone in a phase after parsing where these are mapped to
+ /// already known types, and are converted to ResolvedTypeRef.
+ ///
+ /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
+ UnresolvedTypeRef(clang::Type,
+ Option<clang::Cursor>,
+ /* parent_id */
+ Option<ItemId>),
+
+ /// An indirection to another type.
+ ///
+ /// These are generated after we resolve a forward declaration, or when we
+ /// replace one type with another.
+ ResolvedTypeRef(ItemId),
+
+ /// A named type, that is, a template parameter.
+ Named(String),
+}
+
+impl Type {
+ /// Whether this type is unsized, that is, has no members. This is used to
+ /// derive whether we should generate a dummy `_address` field for structs,
+ /// to comply to the C and C++ layouts, that specify that every type needs
+ /// to be addressable.
+ pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(), "Not yet");
+
+ match self.kind {
+ TypeKind::Void => true,
+ TypeKind::Comp(ref ci) => ci.is_unsized(ctx),
+ TypeKind::Array(inner, size) => {
+ size == 0 || ctx.resolve_type(inner).is_unsized(ctx)
+ }
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateAlias(_, inner, _) |
+ TypeKind::TemplateRef(inner, _) => {
+ ctx.resolve_type(inner).is_unsized(ctx)
+ }
+ TypeKind::Named(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::NullPtr |
+ TypeKind::BlockPointer |
+ TypeKind::Pointer(..) => false,
+
+ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing!");
+ }
+ }
+ }
+
+ /// This is another of the nasty methods. This one is the one that takes
+ /// care of the core logic of converting a clang type to a `Type`.
+ ///
+ /// It's sort of nasty and full of special-casing, but hopefully the
+ /// comments in every special case justify why they're there.
+ pub fn from_clang_ty(potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ {
+ let already_resolved =
+ ctx.builtin_or_resolved_ty(potential_id,
+ parent_id,
+ ty,
+ location);
+ if let Some(ty) = already_resolved {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return Ok(ParseResult::AlreadyResolved(ty));
+ }
+ }
+
+ let layout = ty.fallible_layout().ok();
+ let cursor = ty.declaration();
+ let mut name = cursor.spelling();
+
+ debug!("from_clang_ty: {:?}, ty: {:?}, loc: {:?}",
+ potential_id,
+ ty,
+ location);
+ debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types);
+
+ let canonical_ty = ty.canonical_type();
+ let kind = match ty.kind() {
+ CXType_Unexposed if *ty != canonical_ty &&
+ canonical_ty.kind() != CXType_Invalid => {
+ debug!("Looking for canonical type: {:?}", canonical_ty);
+ return Self::from_clang_ty(potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx);
+ }
+ CXType_Unexposed | CXType_Invalid => {
+ // For some reason Clang doesn't give us any hint in some
+ // situations where we should generate a function pointer (see
+ // tests/headers/func_ptr_in_struct.h), so we do a guess here
+ // trying to see if it has a valid return type.
+ if ty.ret_type().is_some() {
+ let signature = try!(FunctionSig::from_ty(ty,
+ &location.unwrap_or(cursor),
+ ctx));
+ TypeKind::Function(signature)
+ // Same here, with template specialisations we can safely
+ // assume this is a Comp(..)
+ } else if ty.is_fully_specialized_template() {
+ debug!("Template specialization: {:?}", ty);
+ let complex =
+ CompInfo::from_ty(potential_id, ty, location, ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ } else if let Some(location) = location {
+ match location.kind() {
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_CXXBaseSpecifier |
+ CXCursor_ClassTemplate => {
+ if location.kind() == CXCursor_CXXBaseSpecifier {
+ // In the case we're parsing a base specifier
+ // inside an unexposed or invalid type, it means
+ // that we're parsing one of two things:
+ //
+ // * A template parameter.
+ // * A complex class that isn't exposed.
+ //
+ // This means, unfortunately, that there's no
+ // good way to differentiate between them.
+ //
+ // Probably we could try to look at the
+ // declaration and complicate more this logic,
+ // but we'll keep it simple... if it's a valid
+ // C++ identifier, we'll consider it as a
+ // template parameter.
+ //
+ // This is because:
+ //
+ // * We expect every other base that is a
+ // proper identifier (that is, a simple
+ // struct/union declaration), to be exposed,
+ // so this path can't be reached in that
+ // case.
+ //
+ // * Quite conveniently, complex base
+ // specifiers preserve their full names (that
+ // is: Foo<T> instead of Foo). We can take
+ // advantage of this.
+ //
+ // If we find some edge case where this doesn't
+ // work (which I guess is unlikely, see the
+ // different test cases[1][2][3][4]), we'd need
+ // to find more creative ways of differentiating
+ // these two cases.
+ //
+ // [1]: inherit_named.hpp
+ // [2]: forward-inherit-struct-with-fields.hpp
+ // [3]: forward-inherit-struct.hpp
+ // [4]: inherit-namespaced.hpp
+ if location.spelling()
+ .chars()
+ .all(|c| c.is_alphanumeric() || c == '_') {
+ return Err(ParseError::Recurse);
+ }
+ } else {
+ name = location.spelling();
+ }
+ let complex = CompInfo::from_ty(potential_id,
+ ty,
+ Some(location),
+ ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ }
+ CXCursor_TypeAliasTemplateDecl => {
+ debug!("TypeAliasTemplateDecl");
+
+ // We need to manually unwind this one.
+ let mut inner = Err(ParseError::Continue);
+ let mut args = vec![];
+
+ location.visit(|cur| {
+ match cur.kind() {
+ CXCursor_TypeAliasDecl => {
+ let current = cur.cur_type();
+
+ debug_assert!(current.kind() ==
+ CXType_Typedef);
+
+ name = current.spelling();
+
+ let inner_ty = cur.typedef_type()
+ .expect("Not valid Type?");
+ inner =
+ Item::from_ty(&inner_ty,
+ Some(cur),
+ Some(potential_id),
+ ctx);
+ }
+ CXCursor_TemplateTypeParameter => {
+ // See the comment in src/ir/comp.rs
+ // about the same situation.
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let param =
+ Item::named_type(cur.spelling(),
+ potential_id,
+ ctx);
+ args.push(param);
+ }
+ _ => {}
+ }
+ CXChildVisit_Continue
+ });
+
+ let inner_type = match inner {
+ Ok(inner) => inner,
+ Err(..) => {
+ error!("Failed to parse template alias \
+ {:?}",
+ location);
+ return Err(ParseError::Continue);
+ }
+ };
+
+ TypeKind::TemplateAlias(name.clone(),
+ inner_type,
+ args)
+ }
+ CXCursor_TemplateRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+
+ debug!("TemplateRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location,
+ referenced,
+ referenced_ty);
+
+ return Self::from_clang_ty(potential_id,
+ &referenced_ty,
+ Some(referenced),
+ parent_id,
+ ctx);
+ }
+ CXCursor_TypeRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+ let declaration = referenced_ty.declaration();
+
+ debug!("TypeRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location,
+ referenced,
+ referenced_ty);
+
+ let item =
+ Item::from_ty_or_ref_with_id(potential_id,
+ referenced_ty,
+ Some(declaration),
+ parent_id,
+ ctx);
+ return Ok(ParseResult::AlreadyResolved(item));
+ }
+ CXCursor_NamespaceRef => {
+ return Err(ParseError::Continue);
+ }
+ _ => {
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside, \
+ loc: {:?}",
+ ty,
+ location);
+ return Err(ParseError::Recurse);
+ }
+
+ // If the type name is empty we're probably
+ // over-recursing to find a template parameter name
+ // or something like that, so just don't be too
+ // noisy with it since it causes confusion, see for
+ // example the discussion in:
+ //
+ // https://github.com/jamesmunns/teensy3-rs/issues/9
+ if !ty.spelling().is_empty() {
+ warn!("invalid type {:?}", ty);
+ } else {
+ warn!("invalid type {:?}", ty);
+ }
+ return Err(ParseError::Continue);
+ }
+ }
+ } else {
+ // TODO: Don't duplicate this!
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside", ty);
+ return Err(ParseError::Recurse);
+ }
+
+ if !ty.spelling().is_empty() {
+ warn!("invalid type {:?}", ty);
+ } else {
+ warn!("invalid type {:?}", ty);
+ }
+ return Err(ParseError::Continue);
+ }
+ }
+ CXType_Auto => {
+ if canonical_ty == *ty {
+ debug!("Couldn't find deduced type: {:?}", ty);
+ return Err(ParseError::Continue);
+ }
+
+ return Self::from_clang_ty(potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx);
+ }
+ // NOTE: We don't resolve pointers eagerly because the pointee type
+ // might not have been parsed, and if it contains templates or
+ // something else we might get confused, see the comment inside
+ // TypeRef.
+ //
+ // We might need to, though, if the context is already in the
+ // process of resolving them.
+ CXType_MemberPointer |
+ CXType_Pointer => {
+ let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
+ location,
+ parent_id,
+ ctx);
+ TypeKind::Pointer(inner)
+ }
+ CXType_BlockPointer => TypeKind::BlockPointer,
+ // XXX: RValueReference is most likely wrong, but I don't think we
+ // can even add bindings for that, so huh.
+ CXType_RValueReference |
+ CXType_LValueReference => {
+ let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
+ location,
+ parent_id,
+ ctx);
+ TypeKind::Reference(inner)
+ }
+ // XXX DependentSizedArray is wrong
+ CXType_VariableArray |
+ CXType_DependentSizedArray |
+ CXType_IncompleteArray => {
+ let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
+ location,
+ parent_id,
+ ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Pointer(inner)
+ }
+ CXType_FunctionNoProto |
+ CXType_FunctionProto => {
+ let signature = try!(FunctionSig::from_ty(ty,
+ &location.unwrap_or(cursor),
+ ctx));
+ TypeKind::Function(signature)
+ }
+ CXType_Typedef => {
+ let inner = cursor.typedef_type().expect("Not valid Type?");
+ let inner =
+ Item::from_ty_or_ref(inner, location, parent_id, ctx);
+ TypeKind::Alias(ty.spelling(), inner)
+ }
+ CXType_Enum => {
+ let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
+ TypeKind::Enum(enum_)
+ }
+ CXType_Record => {
+ let complex =
+ CompInfo::from_ty(potential_id, ty, location, ctx)
+ .expect("Not a complex type?");
+ TypeKind::Comp(complex)
+ }
+ // FIXME: We stub vectors as arrays since in 99% of the cases the
+ // layout is going to be correct, and there's no way we can generate
+ // vector types properly in Rust for now.
+ //
+ // That being said, that should be fixed eventually.
+ CXType_Vector |
+ CXType_ConstantArray => {
+ let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
+ location,
+ parent_id,
+ ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, ty.num_elements().unwrap())
+ }
+ CXType_Elaborated => {
+ return Self::from_clang_ty(potential_id,
+ &ty.named(),
+ location,
+ parent_id,
+ ctx);
+ }
+ _ => {
+ error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
+ ty.kind(),
+ ty,
+ location);
+ return Err(ParseError::Continue);
+ }
+ };
+
+ let name = if name.is_empty() { None } else { Some(name) };
+ let is_const = ty.is_const();
+
+ let ty = Type::new(name, layout, kind, is_const);
+ // TODO: maybe declaration.canonical()?
+ Ok(ParseResult::New(ty, Some(cursor.canonical())))
+ }
+}
+
+impl TypeCollector for Type {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ match *self.kind() {
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::Array(inner, _) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::ResolvedTypeRef(inner) => {
+ types.insert(inner);
+ }
+
+ TypeKind::TemplateAlias(_, inner, ref template_args) |
+ TypeKind::TemplateRef(inner, ref template_args) => {
+ types.insert(inner);
+ for &item in template_args {
+ types.insert(item);
+ }
+ }
+ TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
+ TypeKind::Function(ref sig) => {
+ sig.collect_types(context, types, item)
+ }
+ TypeKind::Named(_) => {}
+ // FIXME: Pending types!
+ ref other @ _ => {
+ debug!("<Type as TypeCollector>::collect_types: Ignoring: \
+ {:?}",
+ other);
+ }
+ }
+ }
+}
diff --git a/src/ir/type_collector.rs b/src/ir/type_collector.rs
new file mode 100644
index 00000000..0f10152d
--- /dev/null
+++ b/src/ir/type_collector.rs
@@ -0,0 +1,22 @@
+//! Collecting type items.
+
+use std::collections::BTreeSet;
+use super::context::{BindgenContext, ItemId};
+
+/// A set of items.
+pub type ItemSet = BTreeSet<ItemId>;
+
+/// Collect all the type items referenced by this item.
+pub trait TypeCollector {
+ /// If a particular type needs extra information beyond what it has in
+ /// `self` and `context` to find its referenced type items, its
+ /// implementation can define this associated type, forcing callers to pass
+ /// the needed information through.
+ type Extra;
+
+ /// Add each type item referenced by `self` into the `types` set.
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &Self::Extra);
+}
diff --git a/src/ir/var.rs b/src/ir/var.rs
new file mode 100644
index 00000000..329393fa
--- /dev/null
+++ b/src/ir/var.rs
@@ -0,0 +1,317 @@
+//! Intermediate representation of variables.
+
+use cexpr;
+use clang;
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+use std::num::Wrapping;
+use super::context::{BindgenContext, ItemId};
+use super::function::cursor_mangling;
+use super::int::IntKind;
+use super::item::Item;
+use super::ty::{FloatKind, TypeKind};
+
+/// The type for a constant variable.
+#[derive(Debug)]
+pub enum VarType {
+ /// A boolean.
+ Bool(bool),
+ /// An integer.
+ Int(i64),
+ /// A floating point number.
+ Float(f64),
+ /// A character.
+ Char(u8),
+ /// A string, not necessarily well-formed utf-8.
+ String(Vec<u8>),
+}
+
+/// A `Var` is our intermediate representation of a variable.
+#[derive(Debug)]
+pub struct Var {
+ /// The name of the variable.
+ name: String,
+ /// The mangled name of the variable.
+ mangled_name: Option<String>,
+ /// The type of the variable.
+ ty: ItemId,
+ /// The value of the variable, that needs to be suitable for `ty`.
+ val: Option<VarType>,
+ /// Whether this variable is const.
+ is_const: bool,
+}
+
+impl Var {
+ /// Construct a new `Var`.
+ pub fn new(name: String,
+ mangled: Option<String>,
+ ty: ItemId,
+ val: Option<VarType>,
+ is_const: bool)
+ -> Var {
+ assert!(!name.is_empty());
+ Var {
+ name: name,
+ mangled_name: mangled,
+ ty: ty,
+ val: val,
+ is_const: is_const,
+ }
+ }
+
+ /// Is this variable `const` qualified?
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ /// The value of this constant variable, if any.
+ pub fn val(&self) -> Option<&VarType> {
+ self.val.as_ref()
+ }
+
+ /// Get this variable's type.
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ /// Get this variable's name.
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this variable's mangled name.
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+}
+
+impl ClangSubItemParser for Var {
+ fn parse(cursor: clang::Cursor,
+ ctx: &mut BindgenContext)
+ -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ use cexpr::expr::EvalResult;
+ use cexpr::literal::CChar;
+ match cursor.kind() {
+ CXCursor_MacroDefinition => {
+ let value = parse_macro(ctx, &cursor, ctx.translation_unit());
+
+ let (id, value) = match value {
+ Some(v) => v,
+ None => return Err(ParseError::Continue),
+ };
+
+ assert!(!id.is_empty(), "Empty macro name?");
+
+ let previously_defined = ctx.parsed_macro(&id);
+
+ // NB: It's important to "note" the macro even if the result is
+ // not an integer, otherwise we might loose other kind of
+ // derived macros.
+ ctx.note_parsed_macro(id.clone(), value.clone());
+
+ if previously_defined {
+ let name = String::from_utf8(id).unwrap();
+ warn!("Duplicated macro definition: {}", name);
+ return Err(ParseError::Continue);
+ }
+
+ // NOTE: Unwrapping, here and above, is safe, because the
+ // identifier of a token comes straight from clang, and we
+ // enforce utf8 there, so we should have already panicked at
+ // this point.
+ let name = String::from_utf8(id).unwrap();
+ let (type_kind, val) = match value {
+ EvalResult::Invalid => return Err(ParseError::Continue),
+ EvalResult::Float(f) => {
+ (TypeKind::Float(FloatKind::Float), VarType::Float(f))
+ }
+ EvalResult::Char(c) => {
+ let c = match c {
+ CChar::Char(c) => {
+ assert_eq!(c.len_utf8(), 1);
+ c as u8
+ }
+ CChar::Raw(c) => {
+ assert!(c <= ::std::u8::MAX as u64);
+ c as u8
+ }
+ };
+
+ (TypeKind::Int(IntKind::U8), VarType::Char(c))
+ }
+ EvalResult::Str(val) => {
+ let char_ty =
+ Item::builtin_type(TypeKind::Int(IntKind::U8),
+ true,
+ ctx);
+ (TypeKind::Pointer(char_ty), VarType::String(val))
+ }
+ EvalResult::Int(Wrapping(value)) => {
+ let kind = ctx.type_chooser()
+ .and_then(|c| c.int_macro(&name, value))
+ .unwrap_or_else(|| {
+ if value < 0 {
+ if value < i32::min_value() as i64 {
+ IntKind::LongLong
+ } else {
+ IntKind::Int
+ }
+ } else if value > u32::max_value() as i64 {
+ IntKind::ULongLong
+ } else {
+ IntKind::UInt
+ }
+ });
+
+ (TypeKind::Int(kind), VarType::Int(value))
+ }
+ };
+
+ let ty = Item::builtin_type(type_kind, true, ctx);
+
+ Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true),
+ Some(cursor)))
+ }
+ CXCursor_VarDecl => {
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty constant name?");
+ return Err(ParseError::Continue);
+ }
+
+ let ty = cursor.cur_type();
+
+ // XXX this is redundant, remove!
+ let is_const = ty.is_const();
+
+ let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) {
+ Ok(ty) => ty,
+ Err(e) => {
+ assert_eq!(ty.kind(), CXType_Auto,
+ "Couldn't resolve constant type, and it \
+ wasn't an nondeductible auto type!");
+ return Err(e);
+ }
+ };
+
+ // Note: Ty might not be totally resolved yet, see
+ // tests/headers/inner_const.hpp
+ //
+ // That's fine because in that case we know it's not a literal.
+ let canonical_ty = ctx.safe_resolve_type(ty)
+ .and_then(|t| t.safe_canonical_type(ctx));
+
+ let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
+ let is_float = canonical_ty.map_or(false, |t| t.is_float());
+
+ // TODO: We could handle `char` more gracefully.
+ // TODO: Strings, though the lookup is a bit more hard (we need
+ // to look at the canonical type of the pointee too, and check
+ // is char, u8, or i8 I guess).
+ let value = if is_integer {
+ let kind = match *canonical_ty.unwrap().kind() {
+ TypeKind::Int(kind) => kind,
+ _ => unreachable!(),
+ };
+
+ let mut val = cursor.evaluate()
+ .and_then(|v| v.as_int())
+ .map(|val| val as i64);
+ if val.is_none() || !kind.signedness_matches(val.unwrap()) {
+ let tu = ctx.translation_unit();
+ val = get_integer_literal_from_cursor(&cursor, tu);
+ }
+
+ val.map(|val| {
+ if kind == IntKind::Bool {
+ VarType::Bool(val != 0)
+ } else {
+ VarType::Int(val)
+ }
+ })
+ } else if is_float {
+ cursor.evaluate()
+ .and_then(|v| v.as_double())
+ .map(VarType::Float)
+ } else {
+ cursor.evaluate()
+ .and_then(|v| v.as_literal_string())
+ .map(VarType::String)
+ };
+
+ let mangling = cursor_mangling(&cursor);
+ let var = Var::new(name, mangling, ty, value, is_const);
+
+ Ok(ParseResult::New(var, Some(cursor)))
+ }
+ _ => {
+ /* TODO */
+ Err(ParseError::Continue)
+ }
+ }
+ }
+}
+
+/// Try and parse a macro using all the macros parsed until now.
+fn parse_macro(ctx: &BindgenContext,
+ cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit)
+ -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
+ use cexpr::{expr, nom};
+
+ let cexpr_tokens = match unit.cexpr_tokens(cursor) {
+ None => return None,
+ Some(tokens) => tokens,
+ };
+
+ let parser = expr::IdentifierParser::new(ctx.parsed_macros());
+ let result = parser.macro_definition(&cexpr_tokens);
+
+ match result {
+ nom::IResult::Done(_, (id, val)) => Some((id.into(), val)),
+ _ => None,
+ }
+}
+
+fn parse_int_literal_tokens(cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit)
+ -> Option<i64> {
+ use cexpr::{expr, nom};
+ use cexpr::expr::EvalResult;
+
+ let cexpr_tokens = match unit.cexpr_tokens(cursor) {
+ None => return None,
+ Some(tokens) => tokens,
+ };
+
+ // TODO(emilio): We can try to parse other kinds of literals.
+ match expr::expr(&cexpr_tokens) {
+ nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val),
+ _ => None,
+ }
+}
+
+fn get_integer_literal_from_cursor(cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit)
+ -> Option<i64> {
+ use clang_sys::*;
+ let mut value = None;
+ cursor.visit(|c| {
+ match c.kind() {
+ CXCursor_IntegerLiteral |
+ CXCursor_UnaryOperator => {
+ value = parse_int_literal_tokens(&c, unit);
+ }
+ CXCursor_UnexposedExpr => {
+ value = get_integer_literal_from_cursor(&c, unit);
+ }
+ _ => (),
+ }
+ if value.is_some() {
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+ value
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 00000000..60b750de
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,808 @@
+//! Generate Rust bindings for C and C++ libraries.
+//!
+//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
+//! functions and use types defined in the header.
+//!
+//! See the [Builder](./struct.Builder.html) struct for usage.
+
+#![deny(missing_docs)]
+#![deny(warnings)]
+#![deny(unused_extern_crates)]
+
+// We internally use the deprecated BindgenOptions all over the place. Once we
+// remove its `pub` declaration, we can un-deprecate it and remove this pragma.
+#![allow(deprecated)]
+
+// To avoid rather annoying warnings when matching with CXCursor_xxx as a
+// constant.
+#![allow(non_upper_case_globals)]
+
+#[macro_use]
+#[allow(unused_extern_crates)]
+extern crate cfg_if;
+extern crate cexpr;
+extern crate syntex_syntax as syntax;
+extern crate aster;
+extern crate quasi;
+extern crate clang_sys;
+extern crate regex;
+#[macro_use]
+extern crate lazy_static;
+
+#[cfg(feature = "logging")]
+#[macro_use]
+extern crate log;
+
+#[cfg(not(feature = "logging"))]
+#[macro_use]
+mod log_stubs;
+
+// A macro to declare an internal module for which we *must* provide
+// documentation for. If we are building with the "docs_" feature, then the
+// module is declared public, and our `#![deny(missing_docs)]` pragma applies to
+// it. This feature is used in CI, so we won't let anything slip by
+// undocumented. Normal builds, however, will leave the module private, so that
+// we don't expose internals to library consumers.
+macro_rules! doc_mod {
+ ($m:ident, $doc_mod_name:ident) => {
+ cfg_if! {
+ if #[cfg(feature = "docs_")] {
+ pub mod $doc_mod_name {
+ //! Autogenerated documentation module.
+ pub use super::$m::*;
+ }
+ } else {
+ }
+ }
+ };
+}
+
+mod clang;
+mod ir;
+mod parse;
+mod regex_set;
+mod uses;
+
+pub mod chooser;
+
+#[cfg(rustfmt)]
+mod codegen;
+
+doc_mod!(clang, clang_docs);
+doc_mod!(ir, ir_docs);
+doc_mod!(parse, parse_docs);
+doc_mod!(regex_set, regex_set_docs);
+doc_mod!(uses, uses_docs);
+
+mod codegen {
+ include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
+}
+
+use ir::context::{BindgenContext, ItemId};
+use ir::item::Item;
+use parse::{ClangItemParser, ParseError};
+use regex_set::RegexSet;
+
+use std::fs::OpenOptions;
+use std::io::{self, Write};
+use std::path::Path;
+use std::sync::{Arc, Mutex};
+
+use syntax::ast;
+use syntax::codemap::{DUMMY_SP, Span};
+use syntax::print::pp::eof;
+use syntax::print::pprust;
+use syntax::ptr::P;
+
+/// A type used to indicate which kind of items do we have to generate.
+///
+/// TODO(emilio): Use `bitflags!`
+#[derive(Debug, Clone)]
+pub struct CodegenConfig {
+ /// Whether to generate functions.
+ pub functions: bool,
+ /// Whether to generate types.
+ pub types: bool,
+ /// Whether to generate constants.
+ pub vars: bool,
+ /// Whether to generate methods.
+ pub methods: bool,
+ /// Whether to generate constructors.
+ pub constructors: bool,
+}
+
+impl CodegenConfig {
+ /// Generate all kinds of items.
+ pub fn all() -> Self {
+ CodegenConfig {
+ functions: true,
+ types: true,
+ vars: true,
+ methods: true,
+ constructors: true,
+ }
+ }
+
+ /// Generate nothing.
+ pub fn nothing() -> Self {
+ CodegenConfig {
+ functions: false,
+ types: false,
+ vars: false,
+ methods: false,
+ constructors: false,
+ }
+ }
+}
+
+impl Default for CodegenConfig {
+ fn default() -> Self {
+ CodegenConfig::all()
+ }
+}
+
+/// Configure and generate Rust bindings for a C/C++ header.
+///
+/// This is the main entry point to the library.
+///
+/// ```ignore
+/// use bindgen::builder;
+///
+/// // Configure and generate bindings.
+/// let bindings = try!(builder().header("path/to/input/header")
+/// .whitelisted_type("SomeCoolClass")
+/// .whitelisted_function("do_some_cool_thing")
+/// .generate());
+///
+/// // Write the generated bindings to an output file.
+/// try!(bindings.write_to_file("path/to/output.rs"));
+/// ```
+#[derive(Debug,Default)]
+pub struct Builder {
+ options: BindgenOptions,
+}
+
+/// Construct a new [`Builder`](./struct.Builder.html).
+pub fn builder() -> Builder {
+ Default::default()
+}
+
+impl Builder {
+ /// Set the input C/C++ header.
+ pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
+ let header = header.into();
+ self.options.input_header = Some(header);
+ self
+ }
+
+ /// Generate a C/C++ file that includes the header and has dummy uses of
+ /// every type defined in the header.
+ pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
+ self.options.dummy_uses = Some(dummy_uses.into());
+ self
+ }
+
+ /// Hide the given type from the generated bindings.
+ pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.hidden_types.insert(arg);
+ self
+ }
+
+ /// Treat the given type as opaque in the generated bindings.
+ pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.opaque_types.insert(arg);
+ self
+ }
+
+ /// Whitelist the given type so that it (and all types that it transitively
+ /// refers to) appears in the generated bindings.
+ pub fn whitelisted_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.whitelisted_types.insert(arg);
+ self
+ }
+
+ /// Whitelist the given function so that it (and all types that it
+ /// transitively refers to) appears in the generated bindings.
+ pub fn whitelisted_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.whitelisted_functions.insert(arg);
+ self
+ }
+
+ /// Whitelist the given variable so that it (and all types that it
+ /// transitively refers to) appears in the generated bindings.
+ pub fn whitelisted_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.whitelisted_vars.insert(arg);
+ self
+ }
+
+ /// Mark the given enum (or set of enums, if using a pattern) as being
+ /// bitfield-like.
+ ///
+ /// This makes bindgen generate a type that isn't a rust `enum`.
+ pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.bitfield_enums.insert(arg);
+ self
+ }
+
+ /// Add a string to prepend to the generated bindings. The string is passed
+ /// through without any modification.
+ pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.raw_lines.push(arg.into());
+ self
+ }
+
+ /// Add an argument to be passed straight through to clang.
+ pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.clang_args.push(arg.into());
+ self
+ }
+
+ /// Make the generated bindings link the given shared library.
+ pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
+ self.options.links.push((library.into(), LinkType::Default));
+ self
+ }
+
+ /// Make the generated bindings link the given static library.
+ pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
+ self.options.links.push((library.into(), LinkType::Static));
+ self
+ }
+
+ /// Make the generated bindings link the given framework.
+ pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
+ self.options.links.push((library.into(), LinkType::Framework));
+ self
+ }
+
+ /// Emit bindings for builtin definitions (for example `__builtin_va_list`)
+ /// in the generated Rust.
+ pub fn emit_builtins(mut self) -> Builder {
+ self.options.builtins = true;
+ self
+ }
+
+ /// Avoid converting floats to f32/f64 by default.
+ pub fn no_convert_floats(mut self) -> Self {
+ self.options.convert_floats = false;
+ self
+ }
+
+ /// Emit Clang AST.
+ pub fn emit_clang_ast(mut self) -> Builder {
+ self.options.emit_ast = true;
+ self
+ }
+
+ /// Emit IR.
+ pub fn emit_ir(mut self) -> Builder {
+ self.options.emit_ir = true;
+ self
+ }
+
+ /// Enable C++ namespaces.
+ pub fn enable_cxx_namespaces(mut self) -> Builder {
+ self.options.enable_cxx_namespaces = true;
+ self
+ }
+
+ /// Disable auto-namespacing of names if namespaces are disabled.
+ ///
+ /// By default, if namespaces are disabled, bindgen tries to mangle the
+ /// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of
+ /// just `Baz`.
+ ///
+ /// This option disables that behavior.
+ ///
+ /// Note that this intentionally doesn't change the names using for
+ /// whitelisting and blacklisting, that should still be mangled with the
+ /// namespaces.
+ ///
+ /// Note, also, that using this option may cause duplicated names to be
+ /// generated.
+ pub fn disable_name_namespacing(mut self) -> Builder {
+ self.options.disable_name_namespacing = true;
+ self
+ }
+
+ /// Treat inline namespaces conservatively.
+ ///
+ /// This is tricky, because in C++ is technically legal to override an item
+ /// defined in an inline namespace:
+ ///
+ /// ```cpp
+ /// inline namespace foo {
+ /// using Bar = int;
+ /// }
+ /// using Bar = long;
+ /// ```
+ ///
+ /// Even though referencing `Bar` is a compiler error.
+ ///
+ /// We want to support this (arguably esoteric) use case, but we don't want
+ /// to make the rest of bindgen users pay an usability penalty for that.
+ ///
+ /// To support this, we need to keep all the inline namespaces around, but
+ /// then bindgen usage is a bit more difficult, because you cannot
+ /// reference, e.g., `std::string` (you'd need to use the proper inline
+ /// namespace).
+ ///
+ /// We could complicate a lot of the logic to detect name collisions, and if
+ /// not detected generate a `pub use inline_ns::*` or something like that.
+ ///
+ /// That's probably something we can do if we see this option is needed in a
+ /// lot of cases, to improve it's usability, but my guess is that this is
+ /// not going to be too useful.
+ pub fn conservative_inline_namespaces(mut self) -> Builder {
+ self.options.conservative_inline_namespaces = true;
+ self
+ }
+
+ /// Ignore functions.
+ pub fn ignore_functions(mut self) -> Builder {
+ self.options.codegen_config.functions = false;
+ self
+ }
+
+ /// Ignore methods.
+ pub fn ignore_methods(mut self) -> Builder {
+ self.options.codegen_config.methods = false;
+ self
+ }
+
+ /// Avoid generating any unstable Rust in the generated bindings.
+ pub fn no_unstable_rust(mut self) -> Builder {
+ self.options.unstable_rust = false;
+ self
+ }
+
+ /// Use core instead of libstd in the generated bindings.
+ pub fn use_core(mut self) -> Builder {
+ self.options.use_core = true;
+ self
+ }
+
+ /// Use the given prefix for the raw types instead of `::std::os::raw`.
+ pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
+ self.options.ctypes_prefix = Some(prefix.into());
+ self
+ }
+
+ /// Allows configuring types in different situations, see the `TypeChooser`
+ /// documentation.
+ pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self {
+ self.options.type_chooser = Some(cb);
+ self
+ }
+
+ /// Choose what to generate using a CodegenConfig.
+ pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
+ self.options.codegen_config = config;
+ self
+ }
+
+ /// Generate the Rust bindings using the options built up thus far.
+ pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
+ Bindings::generate(self.options, None)
+ }
+}
+
+/// Configuration options for generated bindings.
+///
+/// Deprecated: use a `Builder` instead.
+#[derive(Debug)]
+#[deprecated]
+pub struct BindgenOptions {
+ /// The set of types that have been blacklisted and should not appear
+ /// anywhere in the generated code.
+ pub hidden_types: RegexSet,
+
+ /// The set of types that should be treated as opaque structures in the
+ /// generated code.
+ pub opaque_types: RegexSet,
+
+ /// The set of types that we should have bindings for in the generated
+ /// code.
+ ///
+ /// This includes all types transitively reachable from any type in this
+ /// set. One might think of whitelisted types/vars/functions as GC roots,
+ /// and the generated Rust code as including everything that gets marked.
+ pub whitelisted_types: RegexSet,
+
+ /// Whitelisted functions. See docs for `whitelisted_types` for more.
+ pub whitelisted_functions: RegexSet,
+
+ /// Whitelisted variables. See docs for `whitelisted_types` for more.
+ pub whitelisted_vars: RegexSet,
+
+ /// The enum patterns to mark an enum as bitfield.
+ pub bitfield_enums: RegexSet,
+
+ /// Whether we should generate builtins or not.
+ pub builtins: bool,
+
+ /// The set of libraries we should link in the generated Rust code.
+ pub links: Vec<(String, LinkType)>,
+
+ /// True if we should dump the Clang AST for debugging purposes.
+ pub emit_ast: bool,
+
+ /// True if we should dump our internal IR for debugging purposes.
+ pub emit_ir: bool,
+
+ /// True if we should emulate C++ namespaces with Rust modules in the
+ /// generated bindings.
+ pub enable_cxx_namespaces: bool,
+
+ /// True if we should avoid mangling names with namespaces.
+ pub disable_name_namespacing: bool,
+
+ /// True if we shold derive Debug trait implementations for C/C++ structures
+ /// and types.
+ pub derive_debug: bool,
+
+ /// True if we can use unstable Rust code in the bindings, false if we
+ /// cannot.
+ pub unstable_rust: bool,
+
+ /// True if we should avoid using libstd to use libcore instead.
+ pub use_core: bool,
+
+ /// An optional prefix for the "raw" types, like `c_int`, `c_void`...
+ pub ctypes_prefix: Option<String>,
+
+ /// True if we should generate constant names that are **directly** under
+ /// namespaces.
+ pub namespaced_constants: bool,
+
+ /// True if we should use MSVC name mangling rules.
+ pub msvc_mangling: bool,
+
+ /// Whether we should convert float types to f32/f64 types.
+ pub convert_floats: bool,
+
+ /// The set of raw lines to prepend to the generated Rust code.
+ pub raw_lines: Vec<String>,
+
+ /// The set of arguments to pass straight through to Clang.
+ pub clang_args: Vec<String>,
+
+ /// The input header file.
+ pub input_header: Option<String>,
+
+ /// Generate a dummy C/C++ file that includes the header and has dummy uses
+ /// of all types defined therein. See the `uses` module for more.
+ pub dummy_uses: Option<String>,
+
+ /// A user-provided type chooser to allow customizing different kinds of
+ /// situations.
+ pub type_chooser: Option<Box<chooser::TypeChooser>>,
+
+ /// Which kind of items should we generate? By default, we'll generate all
+ /// of them.
+ pub codegen_config: CodegenConfig,
+
+ /// Whether to treat inline namespaces conservatively.
+ ///
+ /// See the builder method description for more details.
+ pub conservative_inline_namespaces: bool,
+}
+
+impl BindgenOptions {
+ fn build(&mut self) {
+ self.whitelisted_vars.build();
+ self.whitelisted_types.build();
+ self.whitelisted_functions.build();
+ self.hidden_types.build();
+ self.opaque_types.build();
+ self.bitfield_enums.build();
+ }
+}
+
+impl Default for BindgenOptions {
+ fn default() -> BindgenOptions {
+ BindgenOptions {
+ hidden_types: Default::default(),
+ opaque_types: Default::default(),
+ whitelisted_types: Default::default(),
+ whitelisted_functions: Default::default(),
+ whitelisted_vars: Default::default(),
+ bitfield_enums: Default::default(),
+ builtins: false,
+ links: vec![],
+ emit_ast: false,
+ emit_ir: false,
+ derive_debug: true,
+ enable_cxx_namespaces: false,
+ disable_name_namespacing: false,
+ unstable_rust: true,
+ use_core: false,
+ ctypes_prefix: None,
+ namespaced_constants: true,
+ msvc_mangling: false,
+ convert_floats: true,
+ raw_lines: vec![],
+ clang_args: vec![],
+ input_header: None,
+ dummy_uses: None,
+ type_chooser: None,
+ codegen_config: CodegenConfig::all(),
+ conservative_inline_namespaces: false,
+ }
+ }
+}
+
+/// The linking type to use with a given library.
+///
+/// TODO: #104: This is ignored at the moment, but shouldn't be.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum LinkType {
+ /// Use shared library linking. This is the default.
+ Default,
+ /// Use static linking.
+ Static,
+ /// The library is an OSX framework.
+ Framework,
+}
+
+fn ensure_libclang_is_loaded() {
+ if clang_sys::is_loaded() {
+ return;
+ }
+
+ // XXX (issue #350): Ensure that our dynamically loaded `libclang`
+ // doesn't get dropped prematurely, nor is loaded multiple times
+ // across different threads.
+
+ lazy_static! {
+ static ref LIBCLANG: Mutex<Option<Arc<clang_sys::SharedLibrary>>> = {
+ Mutex::new(None)
+ };
+ }
+
+ let mut libclang = LIBCLANG.lock().unwrap();
+ if !clang_sys::is_loaded() {
+ if libclang.is_none() {
+ // TODO(emilio): Return meaningful error (breaking).
+ clang_sys::load().expect("Unable to find libclang");
+ *libclang = Some(clang_sys::get_library()
+ .expect("We just loaded libclang and it had \
+ better still be here!"));
+ } else {
+ clang_sys::set_library(libclang.clone());
+ }
+ }
+}
+
+/// Generated Rust bindings.
+#[derive(Debug)]
+pub struct Bindings<'ctx> {
+ context: BindgenContext<'ctx>,
+ module: ast::Mod,
+}
+
+impl<'ctx> Bindings<'ctx> {
+ /// Generate bindings for the given options.
+ ///
+ /// Deprecated - use a `Builder` instead
+ #[deprecated]
+ pub fn generate(mut options: BindgenOptions,
+ span: Option<Span>)
+ -> Result<Bindings<'ctx>, ()> {
+ let span = span.unwrap_or(DUMMY_SP);
+ ensure_libclang_is_loaded();
+
+ options.build();
+
+ // TODO: Make this path fixup configurable?
+ if let Some(clang) = clang_sys::support::Clang::find(None) {
+ // If --target is specified, assume caller knows what they're doing
+ // and don't mess with include paths for them
+ let has_target_arg = options.clang_args
+ .iter()
+ .rposition(|arg| arg.starts_with("--target"))
+ .is_some();
+ if !has_target_arg {
+ // TODO: distinguish C and C++ paths? C++'s should be enough, I
+ // guess.
+ for path in clang.cpp_search_paths.into_iter() {
+ if let Ok(path) = path.into_os_string().into_string() {
+ options.clang_args.push("-isystem".to_owned());
+ options.clang_args.push(path);
+ }
+ }
+ }
+ }
+
+ if let Some(h) = options.input_header.as_ref() {
+ options.clang_args.push(h.clone())
+ }
+
+ let mut context = BindgenContext::new(options);
+ try!(parse(&mut context));
+
+ let module = ast::Mod {
+ inner: span,
+ items: codegen::codegen(&mut context),
+ };
+
+ Ok(Bindings {
+ context: context,
+ module: module,
+ })
+ }
+
+ /// Convert these bindings into a Rust AST.
+ pub fn into_ast(self) -> Vec<P<ast::Item>> {
+ self.module.items
+ }
+
+ /// Convert these bindings into source text (with raw lines prepended).
+ pub fn to_string(&self) -> String {
+ let mut mod_str = vec![];
+ {
+ let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
+ self.write(ref_writer).expect("Could not write bindings to string");
+ }
+ String::from_utf8(mod_str).unwrap()
+ }
+
+ /// Write these bindings as source text to a file.
+ pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ let file = try!(OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(path));
+ self.write(Box::new(file))
+ }
+
+ /// Write these bindings as source text to the given `Write`able.
+ pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
+ try!(writer.write("/* automatically generated by rust-bindgen */\n\n"
+ .as_bytes()));
+
+ for line in self.context.options().raw_lines.iter() {
+ try!(writer.write(line.as_bytes()));
+ try!(writer.write("\n".as_bytes()));
+ }
+ if !self.context.options().raw_lines.is_empty() {
+ try!(writer.write("\n".as_bytes()));
+ }
+
+ let mut ps = pprust::rust_printer(writer);
+ try!(ps.print_mod(&self.module, &[]));
+ try!(ps.print_remaining_comments());
+ try!(eof(&mut ps.s));
+ ps.s.out.flush()
+ }
+
+ /// Generate and write dummy uses of all the types we parsed, if we've been
+ /// requested to do so in the options.
+ ///
+ /// See the `uses` module for more information.
+ pub fn write_dummy_uses(&mut self) -> io::Result<()> {
+ let file =
+ if let Some(ref dummy_path) = self.context.options().dummy_uses {
+ Some(try!(OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(dummy_path)))
+ } else {
+ None
+ };
+
+ if let Some(file) = file {
+ try!(uses::generate_dummy_uses(&mut self.context, file));
+ }
+
+ Ok(())
+ }
+}
+
+/// Determines whether the given cursor is in any of the files matched by the
+/// options.
+fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
+ let (file, _, _, _) = cursor.location().location();
+
+ match file.name() {
+ None => ctx.options().builtins,
+ Some(..) => true,
+ }
+}
+
+/// Parse one `Item` from the Clang cursor.
+pub fn parse_one(ctx: &mut BindgenContext,
+ cursor: clang::Cursor,
+ parent: Option<ItemId>)
+ -> clang_sys::CXChildVisitResult {
+ if !filter_builtins(ctx, &cursor) {
+ return CXChildVisit_Continue;
+ }
+
+ use clang_sys::CXChildVisit_Continue;
+ match Item::parse(cursor, parent, ctx) {
+ Ok(..) => {}
+ Err(ParseError::Continue) => {}
+ Err(ParseError::Recurse) => {
+ cursor.visit(|child| parse_one(ctx, child, parent));
+ }
+ }
+ CXChildVisit_Continue
+}
+
+/// Parse the Clang AST into our `Item` internal representation.
+fn parse(context: &mut BindgenContext) -> Result<(), ()> {
+ use clang_sys::*;
+
+ let mut any_error = false;
+ for d in context.translation_unit().diags().iter() {
+ let msg = d.format();
+ let is_err = d.severity() >= CXDiagnostic_Error;
+ println!("{}, err: {}", msg, is_err);
+ any_error |= is_err;
+ }
+
+ if any_error {
+ return Err(());
+ }
+
+ let cursor = context.translation_unit().cursor();
+ if context.options().emit_ast {
+ cursor.visit(|cur| clang::ast_dump(&cur, 0));
+ }
+
+ let root = context.root_module();
+ context.with_module(root, |context| {
+ cursor.visit(|cursor| parse_one(context, cursor, None))
+ });
+
+ assert!(context.current_module() == context.root_module(),
+ "How did this happen?");
+ Ok(())
+}
+
+/// Extracted Clang version data
+#[derive(Debug)]
+pub struct ClangVersion {
+ /// Major and minor semvar, if parsing was successful
+ pub parsed: Option<(u32, u32)>,
+ /// full version string
+ pub full: String,
+}
+
+/// Get the major and the minor semvar numbers of Clang's version
+pub fn clang_version() -> ClangVersion {
+ if !clang_sys::is_loaded() {
+ // TODO(emilio): Return meaningful error (breaking).
+ clang_sys::load().expect("Unable to find libclang");
+ }
+
+ let raw_v: String = clang::extract_clang_version();
+ let split_v: Option<Vec<&str>> = raw_v.split_whitespace()
+ .nth(2)
+ .map(|v| v.split('.').collect());
+ match split_v {
+ Some(v) => {
+ if v.len() >= 2 {
+ let maybe_major = v[0].parse::<u32>();
+ let maybe_minor = v[1].parse::<u32>();
+ match (maybe_major, maybe_minor) {
+ (Ok(major), Ok(minor)) => {
+ return ClangVersion {
+ parsed: Some((major, minor)),
+ full: raw_v.clone(),
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ None => {}
+ };
+ ClangVersion {
+ parsed: None,
+ full: raw_v.clone(),
+ }
+}
diff --git a/src/log_stubs.rs b/src/log_stubs.rs
new file mode 100644
index 00000000..4262e120
--- /dev/null
+++ b/src/log_stubs.rs
@@ -0,0 +1,30 @@
+macro_rules! log {
+ (target: $target:expr, $lvl:expr, $($arg)+) => {
+ let _ = $target;
+ let _ = log!($lvl, $($arg)+);
+ };
+ ($lvl:expr, $($arg:tt)+) => {
+ let _ = $lvl;
+ let _ = format_args!($($arg)+);
+ };
+}
+macro_rules! error {
+ (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
+ ($($arg:tt)*) => { log!("", $($arg)*); };
+}
+macro_rules! warn {
+ (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
+ ($($arg:tt)*) => { log!("", $($arg)*); };
+}
+macro_rules! info {
+ (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
+ ($($arg:tt)*) => { log!("", $($arg)*); };
+}
+macro_rules! debug {
+ (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
+ ($($arg:tt)*) => { log!("", $($arg)*); };
+}
+macro_rules! trace {
+ (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
+ ($($arg:tt)*) => { log!("", $($arg)*); };
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 00000000..a7bd9618
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,59 @@
+extern crate bindgen;
+extern crate env_logger;
+#[macro_use]
+extern crate log;
+extern crate clang_sys;
+extern crate clap;
+extern crate rustc_serialize;
+
+use bindgen::clang_version;
+use std::env;
+
+mod options;
+use options::builder_from_flags;
+
+pub fn main() {
+ log::set_logger(|max_log_level| {
+ use env_logger::Logger;
+ let env_logger = Logger::new();
+ max_log_level.set(env_logger.filter());
+ Box::new(env_logger)
+ })
+ .expect("Failed to set logger.");
+
+ let bind_args: Vec<_> = env::args().collect();
+
+ let version = clang_version();
+ let expected_version = if cfg!(feature = "llvm_stable") {
+ (3, 8)
+ } else {
+ (3, 9)
+ };
+
+ info!("Clang Version: {}", version.full);
+
+ match version.parsed {
+ None => warn!("Couldn't parse libclang version"),
+ Some(version) if version != expected_version => {
+ warn!("Using clang {:?}, expected {:?}",
+ version,
+ expected_version);
+ }
+ _ => {}
+ }
+
+ match builder_from_flags(bind_args.into_iter()) {
+ Ok((builder, output)) => {
+ let mut bindings = builder.generate()
+ .expect("Unable to generate bindings");
+ bindings.write(output)
+ .expect("Unable to write output");
+ bindings.write_dummy_uses()
+ .expect("Unable to write dummy uses to file.");
+ }
+ Err(error) => {
+ println!("{}", error);
+ std::process::exit(1);
+ }
+ };
+}
diff --git a/src/options.rs b/src/options.rs
new file mode 100644
index 00000000..3456bfea
--- /dev/null
+++ b/src/options.rs
@@ -0,0 +1,311 @@
+use clap::{App, Arg};
+use bindgen::{Builder, CodegenConfig, builder};
+use std::fs::File;
+use std::io::{self, Error, ErrorKind};
+
+/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
+pub fn builder_from_flags<I>(args: I)
+ -> Result<(Builder, Box<io::Write>), io::Error>
+ where I: Iterator<Item = String>,
+{
+ let matches = App::new("bindgen")
+ .version(env!("CARGO_PKG_VERSION"))
+ .about("Generates Rust bindings from C/C++ headers.")
+ .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
+ .args(&[
+ Arg::with_name("header")
+ .help("C or C++ header file")
+ .required(true),
+ Arg::with_name("bitfield-enum")
+ .long("bitfield-enum")
+ .help("Mark any enum whose name matches <regex> as a set of \
+ bitfield flags instead of an enumeration.")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("blacklist-type")
+ .long("blacklist-type")
+ .help("Mark a type as hidden.")
+ .value_name("type")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("builtins")
+ .long("builtins")
+ .help("Output bindings for builtin definitions, e.g. \
+ __builtin_va_list."),
+ Arg::with_name("ctypes-prefix")
+ .long("ctypes-prefix")
+ .help("Use the given prefix before raw types instead of \
+ ::std::os::raw.")
+ .value_name("prefix")
+ .takes_value(true),
+ // All positional arguments after the end of options marker, `--`
+ Arg::with_name("clang-args")
+ .multiple(true),
+ Arg::with_name("dummy-uses")
+ .long("dummy-uses")
+ .help("For testing purposes, generate a C/C++ file containing \
+ dummy uses of all types defined in the input header.")
+ .takes_value(true),
+ Arg::with_name("emit-clang-ast")
+ .long("emit-clang-ast")
+ .help("Output the Clang AST for debugging purposes."),
+ Arg::with_name("emit-ir")
+ .long("emit-ir")
+ .help("Output our internal IR for debugging purposes."),
+ Arg::with_name("enable-cxx-namespaces")
+ .long("enable-cxx-namespaces")
+ .help("Enable support for C++ namespaces."),
+ Arg::with_name("disable-name-namespacing")
+ .long("disable-name-namespacing")
+ .help("Disable name namespacing if namespaces are disabled."),
+ Arg::with_name("framework")
+ .long("framework-link")
+ .help("Link to framework.")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("ignore-functions")
+ .long("ignore-functions")
+ .help("Do not generate bindings for functions or methods. This \
+ is useful when you only care about struct layouts."),
+ Arg::with_name("generate")
+ .long("generate")
+ .help("Generate a given kind of items, split by commas. \
+ Valid values are \"functions\",\"types\", \"vars\" and \
+ \"methods\".")
+ .takes_value(true),
+ Arg::with_name("ignore-methods")
+ .long("ignore-methods")
+ .help("Do not generate bindings for methods."),
+ Arg::with_name("dynamic")
+ .short("l")
+ .long("link")
+ .help("Link to dynamic library.")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("no-convert-floats")
+ .long("no-convert-floats")
+ .help("Don't automatically convert floats to f32/f64."),
+ Arg::with_name("no-unstable-rust")
+ .long("no-unstable-rust")
+ .help("Do not generate unstable Rust code.")
+ .multiple(true), // FIXME: Pass legacy test suite
+ Arg::with_name("opaque-type")
+ .long("opaque-type")
+ .help("Mark a type as opaque.")
+ .value_name("type")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("output")
+ .short("o")
+ .long("output")
+ .help("Write Rust bindings to <output>.")
+ .takes_value(true),
+ Arg::with_name("raw-line")
+ .long("raw-line")
+ .help("Add a raw line of Rust code at the beginning of output.")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("static")
+ .long("static-link")
+ .help("Link to static library.")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("use-core")
+ .long("use-core")
+ .help("Use types from Rust core instead of std."),
+ Arg::with_name("conservative-inline-namespaces")
+ .long("conservative-inline-namespaces")
+ .help("Conservatively generate inline namespaces to avoid name \
+ conflicts."),
+ Arg::with_name("use-msvc-mangling")
+ .long("use-msvc-mangling")
+ .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."),
+ Arg::with_name("whitelist-function")
+ .long("whitelist-function")
+ .help("Whitelist all the free-standing functions matching \
+ <regex>. Other non-whitelisted functions will not be \
+ generated.")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("whitelist-type")
+ .long("whitelist-type")
+ .help("Whitelist the type. Other non-whitelisted types will \
+ not be generated.")
+ .value_name("type")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("whitelist-var")
+ .long("whitelist-var")
+ .help("Whitelist all the free-standing variables matching \
+ <regex>. Other non-whitelisted variables will not be \
+ generated.")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ ]) // .args()
+ .get_matches_from(args);
+
+ let mut builder = builder();
+
+ if let Some(header) = matches.value_of("header") {
+ builder = builder.header(header);
+ } else {
+ return Err(Error::new(ErrorKind::Other, "Header not found"));
+ }
+
+ if let Some(bitfields) = matches.values_of("bitfield-enum") {
+ for regex in bitfields {
+ builder = builder.bitfield_enum(regex);
+ }
+ }
+
+ if let Some(hidden_types) = matches.values_of("blacklist-type") {
+ for ty in hidden_types {
+ builder = builder.hide_type(ty);
+ }
+ }
+
+ if matches.is_present("builtins") {
+ builder = builder.emit_builtins();
+ }
+
+ if let Some(prefix) = matches.value_of("ctypes-prefix") {
+ builder = builder.ctypes_prefix(prefix);
+ }
+
+ if let Some(dummy) = matches.value_of("dummy-uses") {
+ builder = builder.dummy_uses(dummy);
+ }
+
+ if let Some(links) = matches.values_of("dynamic") {
+ for library in links {
+ builder = builder.link(library);
+ }
+ }
+
+ if let Some(what_to_generate) = matches.value_of("generate") {
+ let mut config = CodegenConfig::nothing();
+ for what in what_to_generate.split(",") {
+ match what {
+ "functions" => config.functions = true,
+ "types" => config.types = true,
+ "vars" => config.vars = true,
+ "methods" => config.methods = true,
+ _ => {
+ return Err(Error::new(ErrorKind::Other,
+ "Unknown generate item"));
+ }
+ }
+ }
+ builder = builder.with_codegen_config(config);
+ }
+
+ if matches.is_present("emit-clang-ast") {
+ builder = builder.emit_clang_ast();
+ }
+
+ if matches.is_present("emit-ir") {
+ builder = builder.emit_ir();
+ }
+
+ if matches.is_present("enable-cxx-namespaces") {
+ builder = builder.enable_cxx_namespaces();
+ }
+
+ if matches.is_present("disable-name-namespacing") {
+ builder = builder.disable_name_namespacing();
+ }
+
+ if let Some(links) = matches.values_of("framework") {
+ for framework in links {
+ builder = builder.link_framework(framework);
+ }
+ }
+
+ if matches.is_present("ignore-functions") {
+ builder = builder.ignore_functions();
+ }
+
+ if matches.is_present("ignore-methods") {
+ builder = builder.ignore_methods();
+ }
+
+ if matches.is_present("no-unstable-rust") {
+ builder = builder.no_unstable_rust();
+ }
+
+ if matches.is_present("no-convert-floats") {
+ builder = builder.no_convert_floats();
+ }
+
+ if let Some(opaque_types) = matches.values_of("opaque-type") {
+ for ty in opaque_types {
+ builder = builder.opaque_type(ty);
+ }
+ }
+
+ if let Some(lines) = matches.values_of("raw-line") {
+ for line in lines {
+ builder = builder.raw_line(line);
+ }
+ }
+
+ if let Some(links) = matches.values_of("static") {
+ for library in links {
+ builder = builder.link_static(library);
+ }
+ }
+
+ if matches.is_present("use-core") {
+ builder = builder.use_core();
+ }
+
+ if matches.is_present("conservative-inline-namespaces") {
+ builder = builder.conservative_inline_namespaces();
+ }
+
+ if let Some(whitelist) = matches.values_of("whitelist-function") {
+ for regex in whitelist {
+ builder = builder.whitelisted_function(regex);
+ }
+ }
+
+ if let Some(whitelist) = matches.values_of("whitelist-type") {
+ for regex in whitelist {
+ builder = builder.whitelisted_type(regex);
+ }
+ }
+
+ if let Some(whitelist) = matches.values_of("whitelist-var") {
+ for regex in whitelist {
+ builder = builder.whitelisted_var(regex);
+ }
+ }
+
+ if let Some(args) = matches.values_of("clang-args") {
+ for arg in args {
+ builder = builder.clang_arg(arg);
+ }
+ }
+
+ let output = if let Some(path) = matches.value_of("output") {
+ let file = try!(File::create(path));
+ Box::new(io::BufWriter::new(file)) as Box<io::Write>
+ } else {
+ Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
+ };
+
+ Ok((builder, output))
+}
diff --git a/src/parse.rs b/src/parse.rs
new file mode 100644
index 00000000..0e4164f0
--- /dev/null
+++ b/src/parse.rs
@@ -0,0 +1,104 @@
+//! Common traits and types related to parsing our IR from Clang cursors.
+
+use clang;
+use ir::context::{BindgenContext, ItemId};
+use ir::ty::TypeKind;
+
+/// Not so much an error in the traditional sense, but a control flow message
+/// when walking over Clang's AST with a cursor.
+#[derive(Debug)]
+pub enum ParseError {
+ /// Recurse down the current AST node's children.
+ Recurse,
+ /// Continue on to the next sibling AST node, or back up to the parent's
+ /// siblings if we've exhausted all of this node's siblings (and so on).
+ Continue,
+}
+
+/// The result of parsing a Clang AST node.
+#[derive(Debug)]
+pub enum ParseResult<T> {
+ /// We've already resolved this item before, here is the extant `ItemId` for
+ /// it.
+ AlreadyResolved(ItemId),
+
+ /// This is a newly parsed item. If the cursor is `Some`, it points to the
+ /// AST node where the new `T` was declared.
+ New(T, Option<clang::Cursor>),
+}
+
+/// An intermediate representation "sub-item" (i.e. one of the types contained
+/// inside an `ItemKind` variant) that can be parsed from a Clang cursor.
+pub trait ClangSubItemParser: Sized {
+ /// Attempt to parse this type from the given cursor.
+ ///
+ /// The fact that is a reference guarantees it's held by the context, and
+ /// allow returning already existing types.
+ fn parse(cursor: clang::Cursor,
+ context: &mut BindgenContext)
+ -> Result<ParseResult<Self>, ParseError>;
+}
+
+/// An intermediate representation item that can be parsed from a Clang cursor.
+pub trait ClangItemParser: Sized {
+ /// Parse this item from the given Clang cursor.
+ fn parse(cursor: clang::Cursor,
+ parent: Option<ItemId>,
+ context: &mut BindgenContext)
+ -> Result<ItemId, ParseError>;
+
+ /// Parse this item from the given Clang type.
+ fn from_ty(ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ItemId, ParseError>;
+
+ /// Identical to `from_ty`, but use the given `id` as the `ItemId` for the
+ /// newly parsed item.
+ fn from_ty_with_id(id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent: Option<ItemId>,
+ ctx: &mut BindgenContext)
+ -> Result<ItemId, ParseError>;
+
+ /// Parse this item from the given Clang type, or if we haven't resolved all
+ /// the other items this one depends on, an unresolved reference.
+ fn from_ty_or_ref(ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext)
+ -> ItemId;
+
+ /// Identical to `from_ty_or_ref`, but use the given `potential_id` as the
+ /// `ItemId` for the newly parsed item.
+ fn from_ty_or_ref_with_id(potential_id: ItemId,
+ ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext)
+ -> ItemId;
+
+ /// Create a named template type.
+ fn named_type<S>(name: S,
+ parent: ItemId,
+ context: &mut BindgenContext)
+ -> ItemId
+ where S: Into<String>;
+
+ /// Identical to `named_type`, but use `id` as the resulting item's
+ /// `ItemId`.
+ fn named_type_with_id<S>(id: ItemId,
+ name: S,
+ parent: ItemId,
+ context: &mut BindgenContext)
+ -> ItemId
+ where S: Into<String>;
+
+ /// Create a builtin type.
+ fn builtin_type(kind: TypeKind,
+ is_const: bool,
+ context: &mut BindgenContext)
+ -> ItemId;
+}
diff --git a/src/regex_set.rs b/src/regex_set.rs
new file mode 100644
index 00000000..dbdb6565
--- /dev/null
+++ b/src/regex_set.rs
@@ -0,0 +1,69 @@
+//! A type that represents the union of a set of regular expressions.
+
+use regex::RegexSet as RxSet;
+
+// Yeah, I'm aware this is sorta crappy, should be cheaper to compile a regex
+// ORing all the patterns, I guess...
+
+/// A dynamic set of regular expressions.
+#[derive(Debug)]
+pub struct RegexSet {
+ items: Vec<String>,
+ set: Option<RxSet>,
+}
+
+impl RegexSet {
+ /// Is this set empty?
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
+ }
+
+ /// Extend this set with every regex in the iterator.
+ pub fn extend<I, S>(&mut self, iter: I)
+ where I: IntoIterator<Item = S>,
+ S: AsRef<str>
+ {
+ for s in iter.into_iter() {
+ self.insert(s)
+ }
+ }
+
+ /// Insert a new regex into this set.
+ pub fn insert<S>(&mut self, string: S)
+ where S: AsRef<str>
+ {
+ self.items.push(format!("^{}$", string.as_ref()));
+ self.set = None;
+ }
+
+ /// Construct a RegexSet from the set of entries we've accumulated.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ pub fn build(&mut self) {
+ self.set = match RxSet::new(&self.items) {
+ Ok(x) => Some(x),
+ Err(e) => {
+ error!("Invalid regex in {:?}: {:?}", self.items, e);
+ None
+ },
+ }
+ }
+
+ /// Does the given `string` match any of the regexes in this set?
+ pub fn matches<S>(&self, string: S) -> bool
+ where S: AsRef<str>
+ {
+ let s = string.as_ref();
+ self.set.as_ref().map(|set| set.is_match(s)).unwrap_or(false)
+ }
+}
+
+impl Default for RegexSet {
+ fn default() -> Self {
+ RegexSet {
+ items: vec![],
+ set: None,
+ }
+ }
+}
diff --git a/src/uses.rs b/src/uses.rs
new file mode 100644
index 00000000..47f72da6
--- /dev/null
+++ b/src/uses.rs
@@ -0,0 +1,102 @@
+//! Take in our IR and output a C/C++ file with dummy uses of each IR type.
+//!
+//! Say that we had this C++ header, `header.hpp`:
+//!
+//! ```c++
+//! class Point {
+//! int x;
+//! int y;
+//! }
+//!
+//! enum Bar {
+//! THIS,
+//! THAT,
+//! OTHER
+//! }
+//! ```
+//!
+//! If we generated dummy uses for this header, we would get a `.cpp` file like
+//! this:
+//!
+//! ```c++
+//! #include "header.hpp"
+//!
+//! void dummy(Point*) {}
+//! void dummy(Bar*) {}
+//! ```
+//!
+//! This is useful because we can compile this `.cpp` file into an object file,
+//! and then compare its debugging information to the debugging information
+//! generated for our Rust bindings. These two sets of debugging information had
+//! better agree on the C/C++ types' physical layout, or else our bindings are
+//! incorrect!
+//!
+//! "But you still haven't explained why we have to generate the dummy uses" you
+//! complain. Well if the types are never used, then they are elided when the
+//! C/C++ compiler generates debugging information.
+
+use ir::context::BindgenContext;
+use ir::item::{Item, ItemAncestors, ItemCanonicalName};
+use std::io;
+
+// Like `canonical_path`, except we always take namespaces into account, ignore
+// the generated names of anonymous items, and return a `String`.
+//
+// TODO: Would it be easier to try and demangle the USR?
+fn namespaced_name(ctx: &BindgenContext, item: &Item) -> String {
+ let mut names: Vec<_> = item.ancestors(ctx)
+ .map(|id| ctx.resolve_item(id).canonical_name(ctx))
+ .filter(|name| !name.starts_with("_bindgen_"))
+ .collect();
+ names.reverse();
+ names.join("::")
+}
+
+/// Generate the dummy uses for all the items in the given context, and write
+/// the dummy uses to `dest`.
+pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext,
+ mut dest: W)
+ -> io::Result<()>
+ where W: io::Write,
+{
+ ctx.gen(|ctx| {
+ let input_header = ctx.options()
+ .input_header
+ .as_ref()
+ .expect("Should not generate dummy uses without an input header");
+
+ try!(writeln!(dest, "/* automatically generated by rust-bindgen */"));
+ try!(writeln!(dest, ""));
+ try!(writeln!(dest, "#include \"{}\"", input_header));
+ try!(writeln!(dest, ""));
+
+ let type_items = ctx.whitelisted_items()
+ .map(|id| ctx.resolve_item(id))
+ .filter(|item| {
+ // We only want type items.
+ if let Some(ty) = item.kind().as_type() {
+ // However, we don't want anonymous types, as we can't
+ // generate dummy uses for them.
+ ty.name().is_some() &&
+ // Nor do we want builtin types or named template type
+ // arguments. Again, we can't generate dummy uses for
+ // these.
+ !ty.is_builtin_or_named() &&
+ // And finally, we won't be creating any dummy
+ // specializations, so ignore template declarations and
+ // partial specializations.
+ item.applicable_template_args(ctx).is_empty()
+ } else {
+ false
+ }
+ })
+ .map(|item| namespaced_name(ctx, item))
+ .enumerate();
+
+ for (idx, name) in type_items {
+ try!(writeln!(dest, "void dummy{}({}*) {{ }}", idx, name));
+ }
+
+ Ok(())
+ })
+}