Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio committed Sep 12, 2016
1 parent 600b282 commit c2aaa08
Show file tree
Hide file tree
Showing 86 changed files with 11,814 additions and 176 deletions.
6 changes: 5 additions & 1 deletion src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl fmt::Debug for Cursor {
pub type CursorVisitor<'s> = for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult + 's;

impl Cursor {
pub fn null() -> Self {
Cursor { x: unsafe { clang_getNullCursor() } }
}

// common
pub fn spelling(&self) -> String {
unsafe {
Expand Down Expand Up @@ -434,7 +438,7 @@ impl Type {

pub fn is_const(&self) -> bool {
unsafe {
clang_isConstQualifiedType(self.x) == 1
clang_isConstQualifiedType(self.x) != 0
}
}

Expand Down
21 changes: 20 additions & 1 deletion src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use ir::layout::Layout;
use std::ops;
use std::mem;
use std::collections::BTreeSet;
use std::collections::HashSet;
use std::collections::hash_map::{HashMap, Entry};

use syntax::abi::Abi;
Expand Down Expand Up @@ -49,20 +50,30 @@ macro_rules! link_name {
struct CodegenResult {
items: Vec<P<ast::Item>>,
saw_union: bool,
items_seen: HashSet<ItemId>,
}

impl CodegenResult {
fn new() -> Self {
CodegenResult {
items: vec![],
saw_union: false,
items_seen: Default::default(),
}
}

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 inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>>
where F: FnOnce(&mut Self)
{
Expand Down Expand Up @@ -249,10 +260,12 @@ impl CodeGenerator for Item {
ctx: &BindgenContext,
result: &mut CodegenResult,
_extra: &()) {
if self.hidden(ctx) {
if self.hidden(ctx) || result.seen(self.id()) {
return;
}

result.set_seen(self.id());

match *self.kind() {
ItemKind::Module(ref module) => {
if !ctx.options().enable_cxx_namespaces && self.id() == ctx.root_module() {
Expand Down Expand Up @@ -365,6 +378,7 @@ impl CodeGenerator for Type {
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.
Expand Down Expand Up @@ -425,6 +439,8 @@ impl CodeGenerator for Type {
result.push(typedef)
}
TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
ref u @ TypeKind::UnresolvedTypeRef(..)
=> unreachable!("Should have been resolved after parsing {:?}!", u),
}
}
}
Expand Down Expand Up @@ -1224,6 +1240,7 @@ impl ToRustTy for Type {

P(inner_ty)
}
TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx),
TypeKind::Alias(ref spelling, inner) => {
if item.opaque(ctx) {
// Pray if there's no available layout.
Expand Down Expand Up @@ -1260,6 +1277,8 @@ impl ToRustTy for Type {
let ident = ctx.rust_ident(&name);
quote_ty!(ctx.ext_cx(), $ident)
}
ref u @ TypeKind::UnresolvedTypeRef(..)
=> unreachable!("Should have been resolved after parsing {:?}!", u),
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,9 @@ impl CompInfo {
for i in 0..len {
let arg_type = ty.template_arg_type(i);
if arg_type.kind() != CXType_Invalid {
let type_id = Item::from_ty(&arg_type, None, None, ctx)
.expect("Type not found in template specialization");
let type_id =
Item::from_ty_or_ref(arg_type, None, None, ctx);

list.push(type_id);
} else {
ci.has_non_type_template_params = true;
Expand Down
45 changes: 44 additions & 1 deletion src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub struct BindgenContext<'ctx> {
/// hard errors while parsing duplicated macros.
parsed_macros: HashSet<String>,

collected_typerefs: bool,

/// Dummy structures for code generation.
gen_ctx: Option<&'ctx GenContext<'ctx>>,
span: Span,
Expand Down Expand Up @@ -100,6 +102,7 @@ impl<'ctx> BindgenContext<'ctx> {
current_module: root_module.id(),
currently_parsed_types: vec![],
parsed_macros: Default::default(),
collected_typerefs: false,
gen_ctx: None,
span: DUMMY_SP,
index: index,
Expand Down Expand Up @@ -195,6 +198,44 @@ impl<'ctx> BindgenContext<'ctx> {
self.items.iter()
}

pub fn collected_typerefs(&self) -> bool {
self.collected_typerefs
}

fn collect_typerefs(&mut self) -> Vec<(ItemId, clang::Type, Option<clang::Cursor>)> {
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,
};

let inner = match *ty.kind() {
TypeKind::UnresolvedTypeRef(ref ty, loc) => {
typerefs.push((*id, ty.clone(), loc));
}
_ => {},
};
}
typerefs
}

fn resolve_typerefs(&mut self) {
let typerefs = self.collect_typerefs();

for (id, ty, loc) in typerefs {
let resolved = Item::from_ty(&ty, loc, None, 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);
}
}

// Enters in the generation phase.
pub fn gen<F, Out>(&mut self, cb: F) -> Out
where F: FnOnce(&Self) -> Out
Expand All @@ -205,6 +246,8 @@ impl<'ctx> BindgenContext<'ctx> {
use syntax::parse;
use std::mem;

self.resolve_typerefs();

let cfg = ExpansionConfig::default("xxx".to_owned());
let sess = parse::ParseSess::new();
let mut loader = base::DummyMacroLoader;
Expand Down Expand Up @@ -263,7 +306,7 @@ impl<'ctx> BindgenContext<'ctx> {
}

pub fn resolve_item(&self, item_id: ItemId) -> &Item {
self.items.get(&item_id).unwrap()
self.items.get(&item_id).expect("Not an item")
}

pub fn current_module(&self) -> ItemId {
Expand Down
54 changes: 49 additions & 5 deletions src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,26 @@ impl Item {
&self.kind
}

pub fn kind_mut(&mut self) -> &mut ItemKind {
&mut self.kind
}

pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
if !ctx.options().enable_cxx_namespaces {
self.parent_id == ctx.root_module()
} else {
self.id() == ctx.root_module()
// FIXME: Workaround for some types falling behind when parsing weird
// stl classes.
if self.kind().is_type() && self.kind().expect_type().is_named() {
return false;
}

let mut parent = ctx.resolve_item(self.parent_id);
loop {
if parent.id() == ctx.root_module() {
return true;
} else if !parent.kind().is_module() {
return false;
}

parent = ctx.resolve_item(parent.parent_id());
}
}

Expand Down Expand Up @@ -168,7 +183,8 @@ impl Item {
TypeKind::Array(inner, _) |
TypeKind::Pointer(inner) |
TypeKind::Reference(inner) |
TypeKind::Alias(_, inner) => {
TypeKind::Alias(_, inner) |
TypeKind::ResolvedTypeRef(inner) => {
ctx.resolve_item(inner).applicable_template_args(ctx)
}
// XXX Is this completely correct? Partial template specialization
Expand Down Expand Up @@ -404,6 +420,34 @@ impl ClangItemParser for Item {
Err(ParseError::Continue)
}

fn from_ty_or_ref(ty: clang::Type,
location: Option<clang::Cursor>,
parent_id: Option<ItemId>,
context: &mut BindgenContext) -> ItemId {
use clangll::*;

if context.collected_typerefs() {
return Self::from_ty(&ty, location, parent_id, context)
.expect("Unable to resolve type");
}

if let Some(ty) = context.builtin_or_resolved_ty(parent_id, &ty, location) {
debug!("{:?} already resolved: {:?}", ty, location);
return ty;
}

let is_const = ty.is_const();
let kind = TypeKind::UnresolvedTypeRef(ty, location);
let id = ItemId::next();
let current_module = context.current_module();
context.add_item(Item::new(id, None, None,
parent_id.unwrap_or(current_module),
ItemKind::Type(Type::new(None, None, kind, is_const))),
Some(clang::Cursor::null()),
None);
id
}

fn from_ty(ty: &clang::Type,
location: Option<clang::Cursor>,
parent_id: Option<ItemId>,
Expand Down
7 changes: 7 additions & 0 deletions src/ir/item_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ impl ItemKind {
}
}

pub fn as_type_mut(&mut self) -> Option<&mut Type> {
match *self {
ItemKind::Type(ref mut ty) => Some(ty),
_ => None,
}
}

pub fn is_type(&self) -> bool {
self.as_type().is_some()
}
Expand Down
42 changes: 36 additions & 6 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ impl Type {
&self.kind
}

pub fn kind_mut(&mut self) -> &mut TypeKind {
&mut self.kind
}

pub fn name(&self) -> Option<&str> {
self.name.as_ref().map(|name| &**name)
}
Expand Down Expand Up @@ -230,9 +234,13 @@ impl Type {
TypeKind::NullPtr |
TypeKind::Pointer(..) => self,

TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).canonical_type(type_resolver),

TypeKind::UnresolvedTypeRef(..)
=> unreachable!("Should have been resolved after parsing!"),
}
}
}
Expand Down Expand Up @@ -278,6 +286,17 @@ pub enum TypeKind {
/// 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>),
ResolvedTypeRef(ItemId),

/// A named type, that is, a template parameter, with an optional default
/// type.
Named(String, Option<ItemId>),
Expand All @@ -292,6 +311,7 @@ impl Type {
size == 0 ||
type_resolver.resolve_type(inner).is_unsized(type_resolver)
}
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).is_unsized(type_resolver),
Expand All @@ -303,6 +323,9 @@ impl Type {
TypeKind::Reference(..) |
TypeKind::NullPtr |
TypeKind::Pointer(..) => false,

TypeKind::UnresolvedTypeRef(..)
=> unreachable!("Should have been resolved after parsing!"),
}
}

Expand Down Expand Up @@ -389,18 +412,25 @@ impl Type {
return Err(ParseError::Continue);
}
}
// 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(&ty.pointee_type(), location, parent_id, ctx)
.expect("Not able to resolve pointee?");
let inner =
Item::from_ty_or_ref(ty.pointee_type(), location, parent_id, ctx);
TypeKind::Pointer(inner)
}
// 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(&ty.pointee_type(), location, parent_id, ctx)
.expect("Not able to resolve pointee?");
let inner =
Item::from_ty_or_ref(ty.pointee_type(), location, parent_id, ctx);
TypeKind::Reference(inner)
}
// XXX DependentSizedArray is wrong
Expand All @@ -418,8 +448,8 @@ impl Type {
}
CXType_Typedef => {
let inner = cursor.typedef_type();
let inner = Item::from_ty(&inner, location, parent_id, ctx)
.expect("Not able to resolve array element?");
let inner =
Item::from_ty_or_ref(inner, location, parent_id, ctx);
TypeKind::Alias(ty.spelling(), inner)
}
CXType_Enum => {
Expand Down
Loading

0 comments on commit c2aaa08

Please sign in to comment.