summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs10
-rw-r--r--src/ir/comp.rs4
-rw-r--r--src/ir/context.rs88
-rw-r--r--src/ir/item.rs10
-rw-r--r--src/ir/named.rs226
-rw-r--r--src/ir/template.rs142
-rw-r--r--src/ir/ty.rs148
-rw-r--r--src/uses.rs2
-rw-r--r--tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs23
-rw-r--r--tests/headers/issue-638-stylo-cannot-find-T-in-this-scope.hpp12
-rwxr-xr-xtests/test-one.sh8
11 files changed, 406 insertions, 267 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 20151fe3..a5df8945 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -21,8 +21,8 @@ use ir::item_kind::ItemKind;
use ir::layout::Layout;
use ir::module::Module;
use ir::objc::{ObjCInterface, ObjCMethod};
-use ir::template::{AsNamed, TemplateInstantiation};
-use ir::ty::{TemplateDeclaration, Type, TypeKind};
+use ir::template::{AsNamed, TemplateInstantiation, TemplateParameters};
+use ir::ty::{Type, TypeKind};
use ir::var::Var;
use std::borrow::Cow;
@@ -2647,8 +2647,10 @@ impl TryToRustTy for TemplateInstantiation {
// This can happen if we generated an opaque type for a partial
// template specialization, and we've hit an instantiation of
// that partial specialization.
- extra_assert!(ctx.resolve_type_through_type_refs(decl)
- .is_opaque());
+ extra_assert!(decl.into_resolver()
+ .through_type_refs()
+ .resolve(ctx)
+ .is_opaque(ctx));
return Err(error::Error::InstantiationOfOpaqueType);
}
};
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 2c7b6de2..80c51b8f 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -6,7 +6,7 @@ use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::TemplateDeclaration;
+use super::template::TemplateParameters;
use clang;
use parse::{ClangItemParser, ParseError};
use std::cell::Cell;
@@ -812,7 +812,7 @@ impl CompInfo {
}
}
-impl TemplateDeclaration for CompInfo {
+impl TemplateParameters for CompInfo {
fn self_template_params(&self,
_ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
diff --git a/src/ir/context.rs b/src/ir/context.rs
index d00e4899..60ea90c6 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -6,9 +6,9 @@ use super::item::{Item, ItemCanonicalPath, ItemSet};
use super::item_kind::ItemKind;
use super::module::{Module, ModuleKind};
use super::named::{UsedTemplateParameters, analyze};
-use super::template::TemplateInstantiation;
+use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
-use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind};
+use super::ty::{FloatKind, Type, TypeKind};
use BindgenOptions;
use cexpr;
use callbacks::ParseCallbacks;
@@ -712,21 +712,6 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
- /// Resolve the given `ItemId` into a `Type`, and keep doing so while we see
- /// `ResolvedTypeRef`s to other items until we get to the final `Type`.
- pub fn resolve_type_through_type_refs(&self, item_id: ItemId) -> &Type {
- assert!(self.collected_typerefs());
-
- let mut id = item_id;
- loop {
- let ty = self.resolve_type(id);
- match *ty.kind() {
- TypeKind::ResolvedTypeRef(next_id) => id = next_id,
- _ => return ty,
- }
- }
- }
-
/// Get the current module.
pub fn current_module(&self) -> ItemId {
self.current_module
@@ -1420,6 +1405,73 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
+/// A builder struct for configuring item resolution options.
+#[derive(Debug, Copy, Clone)]
+pub struct ItemResolver {
+ id: ItemId,
+ through_type_refs: bool,
+ through_type_aliases: bool,
+}
+
+impl ItemId {
+ /// Create an `ItemResolver` from this item id.
+ pub fn into_resolver(self) -> ItemResolver {
+ self.into()
+ }
+}
+
+impl From<ItemId> for ItemResolver {
+ fn from(id: ItemId) -> ItemResolver {
+ ItemResolver::new(id)
+ }
+}
+
+impl ItemResolver {
+ /// Construct a new `ItemResolver` from the given id.
+ pub fn new(id: ItemId) -> ItemResolver {
+ ItemResolver {
+ id: id,
+ through_type_refs: false,
+ through_type_aliases: false,
+ }
+ }
+
+ /// Keep resolving through `Type::TypeRef` items.
+ pub fn through_type_refs(mut self) -> ItemResolver {
+ self.through_type_refs = true;
+ self
+ }
+
+ /// Keep resolving through `Type::Alias` items.
+ pub fn through_type_aliases(mut self) -> ItemResolver {
+ self.through_type_aliases = true;
+ self
+ }
+
+ /// Finish configuring and perform the actual item resolution.
+ pub fn resolve<'a, 'b>(self, ctx: &'a BindgenContext<'b>) -> &'a Item {
+ assert!(ctx.collected_typerefs());
+
+ let mut id = self.id;
+ loop {
+ let item = ctx.resolve_item(id);
+ let ty_kind = item.as_type().map(|t| t.kind());
+ match ty_kind {
+ Some(&TypeKind::ResolvedTypeRef(next_id)) if self.through_type_refs => {
+ id = next_id;
+ }
+ // We intentionally ignore template aliases here, as they are
+ // more complicated, and don't represent a simple renaming of
+ // some type.
+ Some(&TypeKind::Alias(next_id)) if self.through_type_aliases => {
+ id = next_id;
+ }
+ _ => return item,
+ }
+ }
+ }
+}
+
/// A type that we are in the middle of parsing.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PartialType {
@@ -1449,7 +1501,7 @@ impl PartialType {
}
}
-impl TemplateDeclaration for PartialType {
+impl TemplateParameters for PartialType {
fn self_template_params(&self,
_ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 5e806de9..20451bbc 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -8,9 +8,9 @@ use super::function::Function;
use super::item_kind::ItemKind;
use super::layout::Opaque;
use super::module::Module;
-use super::template::AsNamed;
+use super::template::{AsNamed, TemplateParameters};
use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::{TemplateDeclaration, Type, TypeKind};
+use super::ty::{Type, TypeKind};
use clang;
use clang_sys;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
@@ -830,7 +830,7 @@ impl DotAttributes for Item {
}
}
-impl TemplateDeclaration for ItemId {
+impl TemplateParameters for ItemId {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
@@ -839,7 +839,7 @@ impl TemplateDeclaration for ItemId {
}
}
-impl TemplateDeclaration for Item {
+impl TemplateParameters for Item {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
@@ -847,7 +847,7 @@ impl TemplateDeclaration for Item {
}
}
-impl TemplateDeclaration for ItemKind {
+impl TemplateParameters for ItemKind {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
diff --git a/src/ir/named.rs b/src/ir/named.rs
index 2bab5e4e..84a63379 100644
--- a/src/ir/named.rs
+++ b/src/ir/named.rs
@@ -127,10 +127,10 @@
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
use super::context::{BindgenContext, ItemId};
-use super::item::ItemSet;
-use super::template::AsNamed;
+use super::item::{Item, ItemSet};
+use super::template::{AsNamed, TemplateInstantiation, TemplateParameters};
use super::traversal::{EdgeKind, Trace};
-use super::ty::{TemplateDeclaration, TypeKind};
+use super::ty::TypeKind;
use std::collections::{HashMap, HashSet};
use std::fmt;
@@ -212,46 +212,37 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
/// An analysis that finds for each IR item its set of template parameters that
/// it uses.
///
-/// We use the following monotone constraint function:
+/// We use the monotone constraint function `template_param_usage`, defined as
+/// follows:
///
-/// ```ignore
-/// template_param_usage(v) =
-/// self_template_param_usage(v) union
-/// template_param_usage(w_0) union
-/// template_param_usage(w_1) union
-/// ...
-/// template_param_usage(w_n)
-/// ```
-///
-/// Where `v` has direct edges in the IR graph to each of `w_0`, `w_1`,
-/// ..., `w_n` (for example, if `v` were a struct type and `x` and `y`
-/// were the types of two of `v`'s fields). We ignore certain edges, such
-/// as edges from a template declaration to its template parameters'
-/// definitions for this analysis. If we didn't, then we would mistakenly
-/// determine that ever template parameter is always used.
-///
-/// Finally, `self_template_param_usage` is defined with the following cases:
-///
-/// * If `T` is a template parameter:
+/// * If `T` is a named template type parameter, it trivially uses itself:
///
/// ```ignore
-/// self_template_param_usage(T) = { T }
+/// template_param_usage(T) = { T }
/// ```
///
/// * If `inst` is a template instantiation, `inst.args` are the template
-/// instantiation's template arguments, and `inst.decl` is the template
-/// declaration being instantiated:
+/// instantiation's template arguments, and `inst.def` is the template
+/// definition being instantiated:
///
/// ```ignore
-/// self_template_param_usage(inst) =
-/// { T: for T in inst.args, if T in template_param_usage(inst.decl) }
+/// template_param_usage(inst) =
+/// { T: for T in inst.args, if T in template_param_usage(inst.def) }
/// ```
///
-/// * And for all other IR items, the result is the empty set:
+/// * Finally, for all other IR item kinds, we use our lattice's `join`
+/// operation: set union with each successor of the given item's template
+/// parameter usage:
///
/// ```ignore
-/// self_template_param_usage(_) = { }
+/// template_param_usage(v) =
+/// union(template_param_usage(w) for w in successors(v))
/// ```
+///
+/// Note that we ignore certain edges in the graph, such as edges from a
+/// template declaration to its template parameters' definitions for this
+/// analysis. If we didn't, then we would mistakenly determine that ever
+/// template parameter is always used.
#[derive(Debug, Clone)]
pub struct UsedTemplateParameters<'ctx, 'gen>
where 'gen: 'ctx,
@@ -307,6 +298,103 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
EdgeKind::Generic => false,
}
}
+
+ fn take_this_id_usage_set(&mut self, this_id: ItemId) -> ItemSet {
+ self.used
+ .get_mut(&this_id)
+ .expect("Should have a set of used template params for every item \
+ id")
+ .take()
+ .expect("Should maintain the invariant that all used template param \
+ sets are `Some` upon entry of `constrain`")
+ }
+
+ /// We say that blacklisted items use all of their template parameters. The
+ /// blacklisted type is most likely implemented explicitly by the user,
+ /// since it won't be in the generated bindings, and we don't know exactly
+ /// what they'll to with template parameters, but we can push the issue down
+ /// the line to them.
+ fn constrain_instantiation_of_blacklisted_template(&self,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation) {
+ trace!(" instantiation of blacklisted template, uses all template \
+ arguments");
+
+ let args = instantiation.template_arguments()
+ .iter()
+ .filter_map(|a| a.as_named(self.ctx, &()));
+ used_by_this_id.extend(args);
+ }
+
+ /// A template instantiation's concrete template argument is only used if
+ /// the template definition uses the corresponding template parameter.
+ fn constrain_instantiation(&self,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation) {
+ trace!(" template instantiation");
+
+ let decl = self.ctx.resolve_type(instantiation.template_definition());
+ let args = instantiation.template_arguments();
+
+ let params = decl.self_template_params(self.ctx)
+ .unwrap_or(vec![]);
+
+ let used_by_def = self.used[&instantiation.template_definition()]
+ .as_ref()
+ .unwrap();
+
+ for (arg, param) in args.iter().zip(params.iter()) {
+ trace!(" instantiation's argument {:?} is used if definition's \
+ parameter {:?} is used",
+ arg,
+ param);
+
+ if used_by_def.contains(param) {
+ trace!(" param is used by template definition");
+
+ let arg = arg.into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self.ctx);
+ if let Some(named) = arg.as_named(self.ctx, &()) {
+ trace!(" arg is a type parameter, marking used");
+ used_by_this_id.insert(named);
+ }
+ }
+ }
+ }
+
+ /// The join operation on our lattice: the set union of all of this id's
+ /// successors.
+ fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) {
+ trace!(" other item: join with successors' usage");
+
+ item.trace(self.ctx, &mut |sub_id, edge_kind| {
+ // Ignore ourselves, since union with ourself is a
+ // no-op. Ignore edges that aren't relevant to the
+ // analysis. Ignore edges to blacklisted items.
+ if sub_id == item.id() ||
+ !Self::consider_edge(edge_kind) ||
+ !self.whitelisted_items.contains(&sub_id) {
+ return;
+ }
+
+ let used_by_sub_id = self.used[&sub_id]
+ .as_ref()
+ .expect("Because sub_id != id, and all used template \
+ param sets other than id's are `Some`, \
+ sub_id's used template param set should be \
+ `Some`")
+ .iter()
+ .cloned();
+
+ trace!(" union with {:?}'s usage: {:?}",
+ sub_id,
+ used_by_sub_id.clone().collect::<Vec<_>>());
+
+ used_by_this_id.extend(used_by_sub_id);
+ }, &());
+ }
}
impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
@@ -418,13 +506,10 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
// on other hash map entries. We *must* put it back into the hash map at
// the end of this method. This allows us to side-step HashMap's lack of
// an analog to slice::split_at_mut.
- let mut used_by_this_id = self.used
- .get_mut(&id)
- .expect("Should have a set of used template params for every item \
- id")
- .take()
- .expect("Should maintain the invariant that all used template param \
- sets are `Some` upon entry of `constrain`");
+ let mut used_by_this_id = self.take_this_id_usage_set(id);
+
+ trace!("constrain {:?}", id);
+ trace!(" initially, used set is {:?}", used_by_this_id);
let original_len = used_by_this_id.len();
@@ -433,70 +518,26 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
match ty_kind {
// Named template type parameters trivially use themselves.
Some(&TypeKind::Named) => {
+ trace!(" named type, trivially uses itself");
used_by_this_id.insert(id);
}
-
- // We say that blacklisted items use all of their template
- // parameters. The blacklisted type is most likely implemented
- // explicitly by the user, since it won't be in the generated
- // bindings, and we don't know exactly what they'll to with template
- // parameters, but we can push the issue down the line to them.
- Some(&TypeKind::TemplateInstantiation(ref inst))
- if !self.whitelisted_items.contains(&inst.template_definition()) => {
- let args = inst.template_arguments()
- .iter()
- .filter_map(|a| a.as_named(self.ctx, &()));
- used_by_this_id.extend(args);
- }
-
- // A template instantiation's concrete template argument is
- // only used if the template declaration uses the
- // corresponding template parameter.
+ // Template instantiations only use their template arguments if the
+ // template definition uses the corresponding template parameter.
Some(&TypeKind::TemplateInstantiation(ref inst)) => {
- let decl = self.ctx.resolve_type(inst.template_definition());
- let args = inst.template_arguments();
-
- let params = decl.self_template_params(self.ctx)
- .unwrap_or(vec![]);
-
- for (arg, param) in args.iter().zip(params.iter()) {
- let used_by_def = self.used[&inst.template_definition()]
- .as_ref()
- .unwrap();
- if used_by_def.contains(param) {
- if let Some(named) = arg.as_named(self.ctx, &()) {
- used_by_this_id.insert(named);
- }
- }
+ if self.whitelisted_items.contains(&inst.template_definition()) {
+ self.constrain_instantiation(&mut used_by_this_id, inst);
+ } else {
+ self.constrain_instantiation_of_blacklisted_template(&mut used_by_this_id,
+ inst);
}
}
-
// Otherwise, add the union of each of its referent item's template
// parameter usage.
- _ => {
- item.trace(self.ctx, &mut |sub_id, edge_kind| {
- // Ignore ourselves, since union with ourself is a
- // no-op. Ignore edges that aren't relevant to the
- // analysis. Ignore edges to blacklisted items.
- if sub_id == id ||
- !Self::consider_edge(edge_kind) ||
- !self.whitelisted_items.contains(&sub_id) {
- return;
- }
-
- let used_by_sub_id = self.used[&sub_id]
- .as_ref()
- .expect("Because sub_id != id, and all used template \
- param sets other than id's are `Some`, \
- sub_id's used template param set should be \
- `Some`")
- .iter()
- .cloned();
- used_by_this_id.extend(used_by_sub_id);
- }, &());
- }
+ _ => self.constrain_join(&mut used_by_this_id, item),
}
+ trace!(" finally, used set is {:?}", used_by_this_id);
+
let new_len = used_by_this_id.len();
assert!(new_len >= original_len,
"This is the property that ensures this function is monotone -- \
@@ -515,6 +556,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
{
if let Some(edges) = self.dependencies.get(&item) {
for item in edges {
+ trace!("enqueue {:?} into worklist", item);
f(*item);
}
}
diff --git a/src/ir/template.rs b/src/ir/template.rs
index 3484a9c6..d2996330 100644
--- a/src/ir/template.rs
+++ b/src/ir/template.rs
@@ -29,12 +29,152 @@
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
-use super::item::Item;
+use super::item::{Item, ItemAncestors};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;
+/// Template declaration (and such declaration's template parameters) related
+/// methods.
+///
+/// This trait's methods distinguish between `None` and `Some([])` for
+/// declarations that are not templates and template declarations with zero
+/// parameters, in general.
+///
+/// Consider this example:
+///
+/// ```c++
+/// template <typename T, typename U>
+/// class Foo {
+/// T use_of_t;
+/// U use_of_u;
+///
+/// template <typename V>
+/// using Bar = V*;
+///
+/// class Inner {
+/// T x;
+/// U y;
+/// Bar<int> z;
+/// };
+///
+/// template <typename W>
+/// class Lol {
+/// // No use of W, but here's a use of T.
+/// T t;
+/// };
+///
+/// template <typename X>
+/// class Wtf {
+/// // X is not used because W is not used.
+/// Lol<X> lololol;
+/// };
+/// };
+///
+/// class Qux {
+/// int y;
+/// };
+/// ```
+///
+/// The following table depicts the results of each trait method when invoked on
+/// each of the declarations above:
+///
+/// +------+----------------------+--------------------------+------------------------+----
+/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
+/// +------+----------------------+--------------------------+------------------------+----
+/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | ...
+/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | ...
+/// |Inner | None | None | Some([T, U]) | ...
+/// |Lol | Some([W]) | Some(1) | Some([T, U, W]) | ...
+/// |Wtf | Some([X]) | Some(1) | Some([T, U, X]) | ...
+/// |Qux | None | None | None | ...
+/// +------+----------------------+--------------------------+------------------------+----
+///
+/// ----+------+-----+----------------------+
+/// ... |Decl. | ... | used_template_params |
+/// ----+------+-----+----------------------+
+/// ... |Foo | ... | Some([T, U]) |
+/// ... |Bar | ... | Some([V]) |
+/// ... |Inner | ... | None |
+/// ... |Lol | ... | Some([T]) |
+/// ... |Wtf | ... | Some([T]) |
+/// ... |Qux | ... | None |
+/// ----+------+-----+----------------------+
+pub trait TemplateParameters {
+ /// Get the set of `ItemId`s that make up this template declaration's free
+ /// template parameters.
+ ///
+ /// Note that these might *not* all be named types: C++ allows
+ /// constant-value template parameters as well as template-template
+ /// parameters. Of course, Rust does not allow generic parameters to be
+ /// anything but types, so we must treat them as opaque, and avoid
+ /// instantiating them.
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>>;
+
+ /// Get the number of free template parameters this template declaration
+ /// has.
+ ///
+ /// Implementations *may* return `Some` from this method when
+ /// `template_params` returns `None`. This is useful when we only have
+ /// partial information about the template declaration, such as when we are
+ /// in the middle of parsing it.
+ fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
+ self.self_template_params(ctx).map(|params| params.len())
+ }
+
+ /// Get the complete set of template parameters that can affect this
+ /// declaration.
+ ///
+ /// Note that this item doesn't need to be a template declaration itself for
+ /// `Some` to be returned here (in contrast to `self_template_params`). If
+ /// this item is a member of a template declaration, then the parent's
+ /// template parameters are included here.
+ ///
+ /// In the example above, `Inner` depends on both of the `T` and `U` type
+ /// parameters, even though it is not itself a template declaration and
+ /// therefore has no type parameters itself. Perhaps it helps to think about
+ /// how we would fully reference such a member type in C++:
+ /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
+ /// arguments before we can gain access to the `Inner` member type.
+ fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
+ where Self: ItemAncestors,
+ {
+ let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
+ .filter_map(|id| id.self_template_params(ctx))
+ .collect();
+ if each_self_params.is_empty() {
+ None
+ } else {
+ Some(each_self_params.into_iter()
+ .rev()
+ .flat_map(|params| params)
+ .collect())
+ }
+ }
+
+ /// Get only the set of template parameters that this item uses. This is a
+ /// subset of `all_template_params` and does not necessarily contain any of
+ /// `self_template_params`.
+ fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
+ where Self: AsRef<ItemId>,
+ {
+ assert!(ctx.in_codegen_phase(),
+ "template parameter usage is not computed until codegen");
+
+ let id = *self.as_ref();
+ ctx.resolve_item(id)
+ .all_template_params(ctx)
+ .map(|all_params| {
+ all_params.into_iter()
+ .filter(|p| ctx.uses_template_parameter(id, *p))
+ .collect()
+ })
+ }
+}
+
/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
/// Any extra information the implementor might need to make this decision.
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index b47e2bb2..9fabf980 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -7,10 +7,10 @@ use super::dot::DotAttributes;
use super::enum_ty::Enum;
use super::function::FunctionSig;
use super::int::IntKind;
-use super::item::{Item, ItemAncestors};
+use super::item::Item;
use super::layout::{Layout, Opaque};
use super::objc::ObjCInterface;
-use super::template::{AsNamed, TemplateInstantiation};
+use super::template::{AsNamed, TemplateInstantiation, TemplateParameters};
use super::traversal::{EdgeKind, Trace, Tracer};
use clang::{self, Cursor};
use parse::{ClangItemParser, ParseError, ParseResult};
@@ -18,146 +18,6 @@ use std::cell::Cell;
use std::io;
use std::mem;
-/// Template declaration (and such declaration's template parameters) related
-/// methods.
-///
-/// This trait's methods distinguish between `None` and `Some([])` for
-/// declarations that are not templates and template declarations with zero
-/// parameters, in general.
-///
-/// Consider this example:
-///
-/// ```c++
-/// template <typename T, typename U>
-/// class Foo {
-/// T use_of_t;
-/// U use_of_u;
-///
-/// template <typename V>
-/// using Bar = V*;
-///
-/// class Inner {
-/// T x;
-/// U y;
-/// Bar<int> z;
-/// };
-///
-/// template <typename W>
-/// class Lol {
-/// // No use of W, but here's a use of T.
-/// T t;
-/// };
-///
-/// template <typename X>
-/// class Wtf {
-/// // X is not used because W is not used.
-/// Lol<X> lololol;
-/// };
-/// };
-///
-/// class Qux {
-/// int y;
-/// };
-/// ```
-///
-/// The following table depicts the results of each trait method when invoked on
-/// each of the declarations above:
-///
-/// +------+----------------------+--------------------------+------------------------+----
-/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
-/// +------+----------------------+--------------------------+------------------------+----
-/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | ...
-/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | ...
-/// |Inner | None | None | Some([T, U]) | ...
-/// |Lol | Some([W]) | Some(1) | Some([T, U, W]) | ...
-/// |Wtf | Some([X]) | Some(1) | Some([T, U, X]) | ...
-/// |Qux | None | None | None | ...
-/// +------+----------------------+--------------------------+------------------------+----
-///
-/// ----+------+-----+----------------------+
-/// ... |Decl. | ... | used_template_params |
-/// ----+------+-----+----------------------+
-/// ... |Foo | ... | Some([T, U]) |
-/// ... |Bar | ... | Some([V]) |
-/// ... |Inner | ... | None |
-/// ... |Lol | ... | Some([T]) |
-/// ... |Wtf | ... | Some([T]) |
-/// ... |Qux | ... | None |
-/// ----+------+-----+----------------------+
-pub trait TemplateDeclaration {
- /// Get the set of `ItemId`s that make up this template declaration's free
- /// template parameters.
- ///
- /// Note that these might *not* all be named types: C++ allows
- /// constant-value template parameters as well as template-template
- /// parameters. Of course, Rust does not allow generic parameters to be
- /// anything but types, so we must treat them as opaque, and avoid
- /// instantiating them.
- fn self_template_params(&self,
- ctx: &BindgenContext)
- -> Option<Vec<ItemId>>;
-
- /// Get the number of free template parameters this template declaration
- /// has.
- ///
- /// Implementations *may* return `Some` from this method when
- /// `template_params` returns `None`. This is useful when we only have
- /// partial information about the template declaration, such as when we are
- /// in the middle of parsing it.
- fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
- self.self_template_params(ctx).map(|params| params.len())
- }
-
- /// Get the complete set of template parameters that can affect this
- /// declaration.
- ///
- /// Note that this item doesn't need to be a template declaration itself for
- /// `Some` to be returned here (in contrast to `self_template_params`). If
- /// this item is a member of a template declaration, then the parent's
- /// template parameters are included here.
- ///
- /// In the example above, `Inner` depends on both of the `T` and `U` type
- /// parameters, even though it is not itself a template declaration and
- /// therefore has no type parameters itself. Perhaps it helps to think about
- /// how we would fully reference such a member type in C++:
- /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
- /// arguments before we can gain access to the `Inner` member type.
- fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
- where Self: ItemAncestors,
- {
- let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
- .filter_map(|id| id.self_template_params(ctx))
- .collect();
- if each_self_params.is_empty() {
- None
- } else {
- Some(each_self_params.into_iter()
- .rev()
- .flat_map(|params| params)
- .collect())
- }
- }
-
- /// Get only the set of template parameters that this item uses. This is a
- /// subset of `all_template_params` and does not necessarily contain any of
- /// `self_template_params`.
- fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
- where Self: AsRef<ItemId>,
- {
- assert!(ctx.in_codegen_phase(),
- "template parameter usage is not computed until codegen");
-
- let id = *self.as_ref();
- ctx.resolve_item(id)
- .all_template_params(ctx)
- .map(|all_params| {
- all_params.into_iter()
- .filter(|p| ctx.uses_template_parameter(id, *p))
- .collect()
- })
- }
-}
-
/// The base representation of a type in bindgen.
///
/// A type has an optional name, which if present cannot be empty, a `layout`
@@ -623,7 +483,7 @@ fn is_invalid_named_type_empty_name() {
}
-impl TemplateDeclaration for Type {
+impl TemplateParameters for Type {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
@@ -631,7 +491,7 @@ impl TemplateDeclaration for Type {
}
}
-impl TemplateDeclaration for TypeKind {
+impl TemplateParameters for TypeKind {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
diff --git a/src/uses.rs b/src/uses.rs
index 0799011b..fee2be24 100644
--- a/src/uses.rs
+++ b/src/uses.rs
@@ -37,7 +37,7 @@
use ir::context::BindgenContext;
use ir::item::{Item, ItemAncestors, ItemCanonicalName};
-use ir::ty::TemplateDeclaration;
+use ir::template::TemplateParameters;
use std::io;
// Like `canonical_path`, except we always take namespaces into account, ignore
diff --git a/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs
new file mode 100644
index 00000000..4ff0b5bc
--- /dev/null
+++ b/tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs
@@ -0,0 +1,23 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct RefPtr<T> {
+ pub use_of_t: T,
+}
+impl <T> Default for RefPtr<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesRefPtrWithAliasedTypeParam<U> {
+ pub member: RefPtr<UsesRefPtrWithAliasedTypeParam_V<U>>,
+}
+pub type UsesRefPtrWithAliasedTypeParam_V<U> = U;
+impl <U> Default for UsesRefPtrWithAliasedTypeParam<U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/headers/issue-638-stylo-cannot-find-T-in-this-scope.hpp b/tests/headers/issue-638-stylo-cannot-find-T-in-this-scope.hpp
new file mode 100644
index 00000000..13b656e1
--- /dev/null
+++ b/tests/headers/issue-638-stylo-cannot-find-T-in-this-scope.hpp
@@ -0,0 +1,12 @@
+// bindgen-flags: -- -std=c++14
+
+template <class T>
+class RefPtr {
+ T use_of_t;
+};
+
+template <typename U>
+class UsesRefPtrWithAliasedTypeParam {
+ using V = U;
+ RefPtr<V> member;
+};
diff --git a/tests/test-one.sh b/tests/test-one.sh
index 6475df7f..d1950eb9 100755
--- a/tests/test-one.sh
+++ b/tests/test-one.sh
@@ -31,6 +31,14 @@ TEST_BINDINGS_BINARY=$(mktemp -t bindings.XXXXX)
dot -Tpng ir.dot -o ir.png
+echo "=== Input header ========================================================"
+cat "$TEST"
+
+echo "=== Generated bindings =================================================="
+cat "$BINDINGS"
+
+echo "=== Building bindings ==================================================="
rustc --test -o "$TEST_BINDINGS_BINARY" "$BINDINGS"
+echo "=== Testing bindings ===================================================="
"$TEST_BINDINGS_BINARY"