summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/mod.rs35
-rw-r--r--src/ir/context.rs141
-rw-r--r--src/ir/module.rs15
3 files changed, 143 insertions, 48 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 4f0ea371..73aa17c0 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -435,6 +435,16 @@ impl CodeGenerator for Var {
}
result.saw_var(&canonical_name);
+ // We can't generate bindings to static variables of templates. The
+ // number of actual variables for a single declaration are open ended
+ // and we don't know what instantiations do or don't exist.
+ let type_params = item.all_template_params(ctx);
+ if let Some(params) = type_params {
+ if !params.is_empty() {
+ return;
+ }
+ }
+
let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
if let Some(val) = self.val() {
@@ -752,6 +762,13 @@ impl CodeGenerator for TemplateInstantiation {
return
}
+ // If there are any unbound type parameters, then we can't generate a
+ // layout test because we aren't dealing with a concrete type with a
+ // concrete size and alignment.
+ if ctx.uses_any_template_parameters(item.id()) {
+ return;
+ }
+
let layout = item.kind().expect_type().layout(ctx);
if let Some(layout) = layout {
@@ -759,8 +776,11 @@ impl CodeGenerator for TemplateInstantiation {
let align = layout.align;
let name = item.canonical_name(ctx);
- let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}",
- name, item.exposed_id(ctx));
+ let mut fn_name = format!("__bindgen_test_layout_{}_instantiation", name);
+ let times_seen = result.overload_number(&fn_name);
+ if times_seen > 0 {
+ write!(&mut fn_name, "_{}", times_seen).unwrap();
+ }
let fn_name = ctx.rust_ident_raw(&fn_name);
@@ -2920,6 +2940,17 @@ impl CodeGenerator for Function {
item: &Item) {
debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
+ // Similar to static member variables in a class template, we can't
+ // generate bindings to template functions, because the set of
+ // instantiations is open ended and we have no way of knowing which
+ // monomorphizations actually exist.
+ let type_params = item.all_template_params(ctx);
+ if let Some(params) = type_params {
+ if !params.is_empty() {
+ return;
+ }
+ }
+
let name = self.name();
let mut canonical_name = item.canonical_name(ctx);
let mangled_name = self.mangled_name();
diff --git a/src/ir/context.rs b/src/ir/context.rs
index a5ae1962..f61f92e2 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -2,7 +2,7 @@
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::int::IntKind;
-use super::item::{Item, ItemCanonicalPath, ItemSet};
+use super::item::{Item, ItemAncestors, ItemCanonicalPath, ItemSet};
use super::item_kind::ItemKind;
use super::module::{Module, ModuleKind};
use super::named::{UsedTemplateParameters, analyze};
@@ -348,14 +348,8 @@ impl<'ctx> BindgenContext<'ctx> {
let is_template_instantiation =
is_type && item.expect_type().is_template_instantiation();
- // 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());
- }
- }
+ if item.id() != self.root_module {
+ self.add_item_to_module(&item);
}
if is_type && item.expect_type().is_comp() {
@@ -407,6 +401,38 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
+ /// Ensure that every item (other than the root module) is in a module's
+ /// children list. This is to make sure that every whitelisted item get's
+ /// codegen'd, even if its parent is not whitelisted. See issue #769 for
+ /// details.
+ fn add_item_to_module(&mut self, item: &Item) {
+ assert!(item.id() != self.root_module);
+ assert!(!self.items.contains_key(&item.id()));
+
+ if let Some(mut parent) = self.items.get_mut(&item.parent_id()) {
+ if let Some(mut module) = parent.as_module_mut() {
+ debug!("add_item_to_module: adding {:?} as child of parent module {:?}",
+ item.id(),
+ item.parent_id());
+
+ module.children_mut().insert(item.id());
+ return;
+ }
+ }
+
+ debug!("add_item_to_module: adding {:?} as child of current module {:?}",
+ item.id(),
+ self.current_module);
+
+ self.items
+ .get_mut(&self.current_module)
+ .expect("Should always have an item for self.current_module")
+ .as_module_mut()
+ .expect("self.current_module should always be a module")
+ .children_mut()
+ .insert(item.id());
+ }
+
/// Add a new named template type parameter to this context's item set.
pub fn add_named_type(&mut self, item: Item, definition: clang::Cursor) {
debug!("BindgenContext::add_named_type: item = {:?}; definition = {:?}",
@@ -418,6 +444,8 @@ impl<'ctx> BindgenContext<'ctx> {
assert_eq!(definition.kind(),
clang_sys::CXCursor_TemplateTypeParameter);
+ self.add_item_to_module(&item);
+
let id = item.id();
let old_item = self.items.insert(id, item);
assert!(old_item.is_none(),
@@ -620,41 +648,65 @@ impl<'ctx> BindgenContext<'ctx> {
item.parent_id()
};
+ // Relocate the replacement item from where it was declared, to
+ // where the thing it is replacing was declared.
+ //
+ // First, we'll make sure that its parent id is correct.
- // Reparent the item.
let old_parent = self.resolve_item(replacement).parent_id();
-
if new_parent == old_parent {
+ // Same parent and therefore also same containing
+ // module. Nothing to do here.
continue;
}
- if let Some(mut module) = self.items
- .get_mut(&old_parent)
+ self.items
+ .get_mut(&replacement)
.unwrap()
- .as_module_mut() {
- // Deparent the replacement.
- let position = module.children()
- .iter()
- .position(|id| *id == replacement)
- .unwrap();
- module.children_mut().remove(position);
- }
+ .set_parent_for_replacement(new_parent);
- if let Some(mut module) = self.items
- .get_mut(&new_parent)
- .unwrap()
- .as_module_mut() {
- module.children_mut().push(replacement);
+ // Second, make sure that it is in the correct module's children
+ // set.
+
+ let old_module = {
+ let immut_self = &*self;
+ old_parent.ancestors(immut_self)
+ .chain(Some(immut_self.root_module))
+ .find(|id| {
+ let item = immut_self.resolve_item(*id);
+ item.as_module().map_or(false, |m| m.children().contains(&replacement))
+ })
+ };
+ let old_module = old_module.expect("Every replacement item should be in a module");
+
+ let new_module = {
+ let immut_self = &*self;
+ new_parent.ancestors(immut_self).find(|id| {
+ immut_self.resolve_item(*id).is_module()
+ })
+ };
+ let new_module = new_module.unwrap_or(self.root_module);
+
+ if new_module == old_module {
+ // Already in the correct module.
+ continue;
}
self.items
- .get_mut(&replacement)
+ .get_mut(&old_module)
.unwrap()
- .set_parent_for_replacement(new_parent);
+ .as_module_mut()
+ .unwrap()
+ .children_mut()
+ .remove(&replacement);
+
self.items
- .get_mut(&id)
+ .get_mut(&new_module)
+ .unwrap()
+ .as_module_mut()
.unwrap()
- .set_parent_for_replacement(old_parent);
+ .children_mut()
+ .insert(replacement);
}
}
@@ -783,6 +835,21 @@ impl<'ctx> BindgenContext<'ctx> {
.map_or(false, |items_used_params| items_used_params.contains(&template_param))
}
+ /// Return `true` if `item` uses any unbound, generic template parameters,
+ /// `false` otherwise.
+ ///
+ /// Has the same restrictions that `uses_template_parameter` has.
+ pub fn uses_any_template_parameters(&self, item: ItemId) -> bool {
+ assert!(self.in_codegen_phase(),
+ "We only compute template parameter usage as we enter codegen");
+
+ self.used_template_parameters
+ .as_ref()
+ .expect("should have template parameter usage info in codegen phase")
+ .get(&item)
+ .map_or(false, |used| !used.is_empty())
+ }
+
// This deserves a comment. Builtin types don't get a valid declaration, so
// we can't add it to the cursor->type map.
//
@@ -794,6 +861,7 @@ impl<'ctx> BindgenContext<'ctx> {
fn add_builtin_item(&mut self, item: Item) {
debug!("add_builtin_item: item = {:?}", item);
debug_assert!(item.kind().is_type());
+ self.add_item_to_module(&item);
let id = item.id();
let old_item = self.items.insert(id, item);
assert!(old_item.is_none(), "Inserted type twice?");
@@ -932,7 +1000,6 @@ impl<'ctx> BindgenContext<'ctx> {
fn instantiate_template(&mut self,
with_id: ItemId,
template: ItemId,
- parent_id: ItemId,
ty: &clang::Type,
location: clang::Cursor)
-> Option<ItemId> {
@@ -1038,13 +1105,14 @@ impl<'ctx> BindgenContext<'ctx> {
let sub_item = Item::new(sub_id,
None,
None,
- template_decl_id,
+ self.current_module,
ItemKind::Type(sub_ty));
// Bypass all the validations in add_item explicitly.
debug!("instantiate_template: inserting nested \
instantiation item: {:?}",
sub_item);
+ self.add_item_to_module(&sub_item);
debug_assert!(sub_id == sub_item.id());
self.items.insert(sub_id, sub_item);
args.push(sub_id);
@@ -1086,10 +1154,11 @@ impl<'ctx> BindgenContext<'ctx> {
type_kind,
ty.is_const());
let item =
- Item::new(with_id, None, None, parent_id, ItemKind::Type(ty));
+ Item::new(with_id, None, None, self.current_module, ItemKind::Type(ty));
// Bypass all the validations in add_item explicitly.
debug!("instantiate_template: inserting item: {:?}", item);
+ self.add_item_to_module(&item);
debug_assert!(with_id == item.id());
self.items.insert(with_id, item);
Some(with_id)
@@ -1143,11 +1212,6 @@ impl<'ctx> BindgenContext<'ctx> {
location.is_some() {
let location = location.unwrap();
- // It is always safe to hang instantiations off of the root
- // module. They use their template definition for naming,
- // and don't need the parent for anything else.
- let parent_id = self.root_module();
-
// 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).
@@ -1166,7 +1230,6 @@ impl<'ctx> BindgenContext<'ctx> {
return self.instantiate_template(with_id,
id,
- parent_id,
ty,
location)
.or_else(|| Some(id));
diff --git a/src/ir/module.rs b/src/ir/module.rs
index ee3912c5..09070247 100644
--- a/src/ir/module.rs
+++ b/src/ir/module.rs
@@ -1,7 +1,8 @@
//! Intermediate representation for modules (AKA C++ namespaces).
-use super::context::{BindgenContext, ItemId};
+use super::context::BindgenContext;
use super::dot::DotAttributes;
+use super::item::ItemSet;
use clang;
use parse::{ClangSubItemParser, ParseError, ParseResult};
use parse_one;
@@ -24,7 +25,7 @@ pub struct Module {
/// The kind of module this is.
kind: ModuleKind,
/// The children of this module, just here for convenience.
- children_ids: Vec<ItemId>,
+ children: ItemSet,
}
impl Module {
@@ -33,7 +34,7 @@ impl Module {
Module {
name: name,
kind: kind,
- children_ids: vec![],
+ children: ItemSet::new(),
}
}
@@ -43,13 +44,13 @@ impl Module {
}
/// Get a mutable reference to this module's children.
- pub fn children_mut(&mut self) -> &mut Vec<ItemId> {
- &mut self.children_ids
+ pub fn children_mut(&mut self) -> &mut ItemSet {
+ &mut self.children
}
/// Get this module's children.
- pub fn children(&self) -> &[ItemId] {
- &self.children_ids
+ pub fn children(&self) -> &ItemSet {
+ &self.children
}
/// Whether this namespace is inline.