From 8fc90585593c011c5a5be03278d6b785db5f16b8 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 13:23:22 -0700 Subject: [PATCH 1/9] Make a builder for item resolution options We have a couple knobs to turn for item resolution, such as whether we keep going through type references and type aliases. It makes sense to have a single, easy place to configure these knobs. --- src/codegen/mod.rs | 6 ++-- src/ir/context.rs | 82 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 20151fe3e5..950de02a42 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -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/context.rs b/src/ir/context.rs index d00e489938..01416c9e6d 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -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 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 { From a72b7952abe7f3d8d8755f9e33175dd2ce961650 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 14:20:01 -0700 Subject: [PATCH 2/9] Add debug!(..) logging for the template type parameters analysis This commit adds a bunch of debug logging to the template type parameters analysis. I've essentially adding this same code and then never committed it, like three or four different times. Because I keep re-writing it, I think it is worth keeping around in a more permanent fashion. --- src/ir/named.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ir/named.rs b/src/ir/named.rs index 2bab5e4e9e..39fa220129 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -426,6 +426,9 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { .expect("Should maintain the invariant that all used template param \ sets are `Some` upon entry of `constrain`"); + debug!("constrain {:?}", id); + debug!(" initially, used set is {:?}", used_by_this_id); + let original_len = used_by_this_id.len(); let item = self.ctx.resolve_item(id); @@ -433,6 +436,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { match ty_kind { // Named template type parameters trivially use themselves. Some(&TypeKind::Named) => { + debug!(" named type, trivially uses itself"); used_by_this_id.insert(id); } @@ -443,6 +447,9 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // 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()) => { + debug!(" instantiation of blacklisted template, uses all template \ + arguments"); + let args = inst.template_arguments() .iter() .filter_map(|a| a.as_named(self.ctx, &())); @@ -453,18 +460,29 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // only used if the template declaration uses the // corresponding template parameter. Some(&TypeKind::TemplateInstantiation(ref inst)) => { + debug!(" template instantiation"); + 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![]); + let used_by_def = self.used[&inst.template_definition()] + .as_ref() + .unwrap(); + for (arg, param) in args.iter().zip(params.iter()) { - let used_by_def = self.used[&inst.template_definition()] - .as_ref() - .unwrap(); + debug!(" instantiation's argument {:?} is used if definition's \ + parameter {:?} is used", + arg, + param); + if used_by_def.contains(param) { + debug!(" param is used by template definition"); + if let Some(named) = arg.as_named(self.ctx, &()) { + debug!(" arg is a type parameter, marking used"); used_by_this_id.insert(named); } } @@ -474,6 +492,8 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // Otherwise, add the union of each of its referent item's template // parameter usage. _ => { + debug!(" 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 @@ -492,11 +512,18 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { `Some`") .iter() .cloned(); + + debug!(" union with {:?}'s usage: {:?}", + sub_id, + used_by_sub_id.clone().collect::>()); + used_by_this_id.extend(used_by_sub_id); }, &()); } } + debug!(" 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 +542,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { { if let Some(edges) = self.dependencies.get(&item) { for item in edges { + debug!("enqueue {:?} into worklist", item); f(*item); } } From 790826272861bd3eca2d149ac7b2b95fcbec6e09 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 14:37:19 -0700 Subject: [PATCH 3/9] Add more diagnostic output to the test-one.sh script This commit makes the test-one.sh script log the input header as well as the emitted bindings to stdout. --- tests/test-one.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test-one.sh b/tests/test-one.sh index 6475df7f8b..d1950eb904 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" From bce13307645172be62e8895e82d9362f0c4e4fd6 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 14:40:29 -0700 Subject: [PATCH 4/9] Resolve through type refs and aliases when marking type params used In stylo bindings generation, we were hitting bugs where the analysis saw a template type parameter behind a type ref to a type alias, and this was then used as an argument to a template instantiation. Because of the indirection, the analysis got confused and ignored the template argument because it was "not" a named template type, and therefore we didn't care about its usage. This commit makes sure that we keep resolving through type references and aliases to find the inner named template type parameter to add to the current item's usage set. Fixes #638. --- src/ir/named.rs | 4 ++++ ...e-638-stylo-cannot-find-T-in-this-scope.rs | 23 +++++++++++++++++++ ...-638-stylo-cannot-find-T-in-this-scope.hpp | 12 ++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/expectations/tests/issue-638-stylo-cannot-find-T-in-this-scope.rs create mode 100644 tests/headers/issue-638-stylo-cannot-find-T-in-this-scope.hpp diff --git a/src/ir/named.rs b/src/ir/named.rs index 39fa220129..17f46eca71 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -481,6 +481,10 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { if used_by_def.contains(param) { debug!(" 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, &()) { debug!(" arg is a type parameter, marking used"); used_by_this_id.insert(named); 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 0000000000..4ff0b5bc21 --- /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 { + pub use_of_t: T, +} +impl Default for RefPtr { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesRefPtrWithAliasedTypeParam { + pub member: RefPtr>, +} +pub type UsesRefPtrWithAliasedTypeParam_V = U; +impl Default for UsesRefPtrWithAliasedTypeParam { + 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 0000000000..13b656e156 --- /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 RefPtr { + T use_of_t; +}; + +template +class UsesRefPtrWithAliasedTypeParam { + using V = U; + RefPtr member; +}; From 1c78209eea25c79676945af371a523ed023ce46a Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 15:07:59 -0700 Subject: [PATCH 5/9] Factor the `UsedTemplateParameters::constrain` method into smaller functions The method was getting fairly large, and it is a little easier to read if we break it down into smaller parts. --- src/ir/named.rs | 197 ++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 89 deletions(-) diff --git a/src/ir/named.rs b/src/ir/named.rs index 17f46eca71..855da00551 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -127,8 +127,8 @@ //! [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}; use super::traversal::{EdgeKind, Trace}; use super::ty::{TemplateDeclaration, TypeKind}; use std::collections::{HashMap, HashSet}; @@ -307,6 +307,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) { + debug!(" 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) { + debug!(" 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()) { + debug!(" instantiation's argument {:?} is used if definition's \ + parameter {:?} is used", + arg, + param); + + if used_by_def.contains(param) { + debug!(" 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, &()) { + debug!(" 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) { + debug!(" 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(); + + debug!(" union with {:?}'s usage: {:?}", + sub_id, + used_by_sub_id.clone().collect::>()); + + used_by_this_id.extend(used_by_sub_id); + }, &()); + } } impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { @@ -418,13 +515,7 @@ 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); debug!("constrain {:?}", id); debug!(" initially, used set is {:?}", used_by_this_id); @@ -439,91 +530,19 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { debug!(" 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()) => { - debug!(" instantiation of blacklisted template, uses all template \ - arguments"); - - 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)) => { - debug!(" template instantiation"); - - 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![]); - - let used_by_def = self.used[&inst.template_definition()] - .as_ref() - .unwrap(); - - for (arg, param) in args.iter().zip(params.iter()) { - debug!(" instantiation's argument {:?} is used if definition's \ - parameter {:?} is used", - arg, - param); - - if used_by_def.contains(param) { - debug!(" 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, &()) { - debug!(" arg is a type parameter, marking used"); - 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. - _ => { - debug!(" 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 == 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(); - - debug!(" union with {:?}'s usage: {:?}", - sub_id, - used_by_sub_id.clone().collect::>()); - - used_by_this_id.extend(used_by_sub_id); - }, &()); - } + _ => self.constrain_join(&mut used_by_this_id, item), } debug!(" finally, used set is {:?}", used_by_this_id); From 72bbb9045ccabc3392dc20691ddf902b4f281f92 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 15:23:14 -0700 Subject: [PATCH 6/9] Fix template usage analysis doc comment It had some incorrectness where there was a difference between the abstract `self_template_param_usage` and `template_param_usage` functions. In reality, they are different cases of the same function. The comment was misleading in that it implied that we run both on the same IR item, when in fact we will only run one or the other. I've tried to make it more clear in the new version of the comment. --- src/ir/named.rs | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/ir/named.rs b/src/ir/named.rs index 855da00551..4ff9ed91b8 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -212,46 +212,37 @@ pub fn analyze(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, From 19265360b417a905b6c7acf2afe7c603d7b7afa8 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 15:27:48 -0700 Subject: [PATCH 7/9] Rename the `TemplateDeclaration` trait to `TemplateParameters` The trait is all about accessing template parameters, and is also implemented for things that are not template declarations or definitions, but do end up using template parameters one way or another. The new name makes more sense. --- src/codegen/mod.rs | 2 +- src/ir/comp.rs | 4 ++-- src/ir/context.rs | 4 ++-- src/ir/item.rs | 8 ++++---- src/ir/named.rs | 2 +- src/ir/ty.rs | 7 ++++--- src/uses.rs | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 950de02a42..0785f2fdef 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -22,7 +22,7 @@ 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::ty::{TemplateParameters, Type, TypeKind}; use ir::var::Var; use std::borrow::Cow; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 2c7b6de239..8a796e5e1e 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::ty::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> { diff --git a/src/ir/context.rs b/src/ir/context.rs index 01416c9e6d..6cf3cdcd61 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -8,7 +8,7 @@ use super::module::{Module, ModuleKind}; use super::named::{UsedTemplateParameters, analyze}; use super::template::TemplateInstantiation; use super::traversal::{self, Edge, ItemTraversal}; -use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind}; +use super::ty::{FloatKind, TemplateParameters, Type, TypeKind}; use BindgenOptions; use cexpr; use callbacks::ParseCallbacks; @@ -1501,7 +1501,7 @@ impl PartialType { } } -impl TemplateDeclaration for PartialType { +impl TemplateParameters for PartialType { fn self_template_params(&self, _ctx: &BindgenContext) -> Option> { diff --git a/src/ir/item.rs b/src/ir/item.rs index 5e806de97c..5d95130f7d 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -10,7 +10,7 @@ use super::layout::Opaque; use super::module::Module; use super::template::AsNamed; use super::traversal::{EdgeKind, Trace, Tracer}; -use super::ty::{TemplateDeclaration, Type, TypeKind}; +use super::ty::{TemplateParameters, 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> { @@ -839,7 +839,7 @@ impl TemplateDeclaration for ItemId { } } -impl TemplateDeclaration for Item { +impl TemplateParameters for Item { fn self_template_params(&self, ctx: &BindgenContext) -> Option> { @@ -847,7 +847,7 @@ impl TemplateDeclaration for Item { } } -impl TemplateDeclaration for ItemKind { +impl TemplateParameters for ItemKind { fn self_template_params(&self, ctx: &BindgenContext) -> Option> { diff --git a/src/ir/named.rs b/src/ir/named.rs index 4ff9ed91b8..1493b17058 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -130,7 +130,7 @@ use super::context::{BindgenContext, ItemId}; use super::item::{Item, ItemSet}; use super::template::{AsNamed, TemplateInstantiation}; use super::traversal::{EdgeKind, Trace}; -use super::ty::{TemplateDeclaration, TypeKind}; +use super::ty::{TemplateParameters, TypeKind}; use std::collections::{HashMap, HashSet}; use std::fmt; diff --git a/src/ir/ty.rs b/src/ir/ty.rs index b47e2bb20d..0b1cf558ee 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -84,7 +84,8 @@ use std::mem; /// ... |Wtf | ... | Some([T]) | /// ... |Qux | ... | None | /// ----+------+-----+----------------------+ -pub trait TemplateDeclaration { + +pub trait TemplateParameters { /// Get the set of `ItemId`s that make up this template declaration's free /// template parameters. /// @@ -623,7 +624,7 @@ fn is_invalid_named_type_empty_name() { } -impl TemplateDeclaration for Type { +impl TemplateParameters for Type { fn self_template_params(&self, ctx: &BindgenContext) -> Option> { @@ -631,7 +632,7 @@ impl TemplateDeclaration for Type { } } -impl TemplateDeclaration for TypeKind { +impl TemplateParameters for TypeKind { fn self_template_params(&self, ctx: &BindgenContext) -> Option> { diff --git a/src/uses.rs b/src/uses.rs index 0799011b36..40344dd6b2 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::ty::TemplateParameters; use std::io; // Like `canonical_path`, except we always take namespaces into account, ignore From 1fcfca5e4dedb812e88d5ea5346d25dc6165fbe1 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 15:38:06 -0700 Subject: [PATCH 8/9] Move the TemplateParameters trait from ir::ty to ir::template Organizationally, it makes more sense. --- src/codegen/mod.rs | 4 +- src/ir/comp.rs | 2 +- src/ir/context.rs | 4 +- src/ir/item.rs | 4 +- src/ir/named.rs | 4 +- src/ir/template.rs | 142 +++++++++++++++++++++++++++++++++++++++++++- src/ir/ty.rs | 145 +-------------------------------------------- src/uses.rs | 2 +- 8 files changed, 153 insertions(+), 154 deletions(-) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 0785f2fdef..a5df8945ee 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::{TemplateParameters, Type, TypeKind}; +use ir::template::{AsNamed, TemplateInstantiation, TemplateParameters}; +use ir::ty::{Type, TypeKind}; use ir::var::Var; use std::borrow::Cow; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 8a796e5e1e..80c51b8f3e 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::TemplateParameters; +use super::template::TemplateParameters; use clang; use parse::{ClangItemParser, ParseError}; use std::cell::Cell; diff --git a/src/ir/context.rs b/src/ir/context.rs index 6cf3cdcd61..60ea90c6bc 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, TemplateParameters, Type, TypeKind}; +use super::ty::{FloatKind, Type, TypeKind}; use BindgenOptions; use cexpr; use callbacks::ParseCallbacks; diff --git a/src/ir/item.rs b/src/ir/item.rs index 5d95130f7d..20451bbc1b 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::{TemplateParameters, Type, TypeKind}; +use super::ty::{Type, TypeKind}; use clang; use clang_sys; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; diff --git a/src/ir/named.rs b/src/ir/named.rs index 1493b17058..82fd674c5b 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -128,9 +128,9 @@ use super::context::{BindgenContext, ItemId}; use super::item::{Item, ItemSet}; -use super::template::{AsNamed, TemplateInstantiation}; +use super::template::{AsNamed, TemplateInstantiation, TemplateParameters}; use super::traversal::{EdgeKind, Trace}; -use super::ty::{TemplateParameters, TypeKind}; +use super::ty::TypeKind; use std::collections::{HashMap, HashSet}; use std::fmt; diff --git a/src/ir/template.rs b/src/ir/template.rs index 3484a9c6e7..d29963302f 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 +/// class Foo { +/// T use_of_t; +/// U use_of_u; +/// +/// template +/// using Bar = V*; +/// +/// class Inner { +/// T x; +/// U y; +/// Bar z; +/// }; +/// +/// template +/// class Lol { +/// // No use of W, but here's a use of T. +/// T t; +/// }; +/// +/// template +/// class Wtf { +/// // X is not used because W is not used. +/// Lol 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>; + + /// 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 { + 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::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> + where Self: ItemAncestors, + { + let each_self_params: 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> + where Self: AsRef, + { + 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 0b1cf558ee..9fabf98087 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,147 +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 -/// class Foo { -/// T use_of_t; -/// U use_of_u; -/// -/// template -/// using Bar = V*; -/// -/// class Inner { -/// T x; -/// U y; -/// Bar z; -/// }; -/// -/// template -/// class Lol { -/// // No use of W, but here's a use of T. -/// T t; -/// }; -/// -/// template -/// class Wtf { -/// // X is not used because W is not used. -/// Lol 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>; - - /// 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 { - 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::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> - where Self: ItemAncestors, - { - let each_self_params: 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> - where Self: AsRef, - { - 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` diff --git a/src/uses.rs b/src/uses.rs index 40344dd6b2..fee2be24ed 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::TemplateParameters; +use ir::template::TemplateParameters; use std::io; // Like `canonical_path`, except we always take namespaces into account, ignore From 9689db6027d733a9d4fb6c7e385620022efaa2bd Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 17 Apr 2017 16:34:37 -0700 Subject: [PATCH 9/9] Use `trace!` instead of `debug!` logging in the template analysis These logs are pretty loud, so let's knock em down a log level. --- src/ir/named.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ir/named.rs b/src/ir/named.rs index 82fd674c5b..84a633795b 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -317,7 +317,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { fn constrain_instantiation_of_blacklisted_template(&self, used_by_this_id: &mut ItemSet, instantiation: &TemplateInstantiation) { - debug!(" instantiation of blacklisted template, uses all template \ + trace!(" instantiation of blacklisted template, uses all template \ arguments"); let args = instantiation.template_arguments() @@ -331,7 +331,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { fn constrain_instantiation(&self, used_by_this_id: &mut ItemSet, instantiation: &TemplateInstantiation) { - debug!(" template instantiation"); + trace!(" template instantiation"); let decl = self.ctx.resolve_type(instantiation.template_definition()); let args = instantiation.template_arguments(); @@ -344,20 +344,20 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { .unwrap(); for (arg, param) in args.iter().zip(params.iter()) { - debug!(" instantiation's argument {:?} is used if definition's \ + trace!(" instantiation's argument {:?} is used if definition's \ parameter {:?} is used", arg, param); if used_by_def.contains(param) { - debug!(" param is used by template definition"); + 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, &()) { - debug!(" arg is a type parameter, marking used"); + trace!(" arg is a type parameter, marking used"); used_by_this_id.insert(named); } } @@ -367,7 +367,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { /// 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) { - debug!(" other item: join with successors' usage"); + trace!(" other item: join with successors' usage"); item.trace(self.ctx, &mut |sub_id, edge_kind| { // Ignore ourselves, since union with ourself is a @@ -388,7 +388,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { .iter() .cloned(); - debug!(" union with {:?}'s usage: {:?}", + trace!(" union with {:?}'s usage: {:?}", sub_id, used_by_sub_id.clone().collect::>()); @@ -508,8 +508,8 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { // an analog to slice::split_at_mut. let mut used_by_this_id = self.take_this_id_usage_set(id); - debug!("constrain {:?}", id); - debug!(" initially, used set is {:?}", used_by_this_id); + trace!("constrain {:?}", id); + trace!(" initially, used set is {:?}", used_by_this_id); let original_len = used_by_this_id.len(); @@ -518,7 +518,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { match ty_kind { // Named template type parameters trivially use themselves. Some(&TypeKind::Named) => { - debug!(" named type, trivially uses itself"); + trace!(" named type, trivially uses itself"); used_by_this_id.insert(id); } // Template instantiations only use their template arguments if the @@ -536,7 +536,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { _ => self.constrain_join(&mut used_by_this_id, item), } - debug!(" finally, used set is {:?}", used_by_this_id); + trace!(" finally, used set is {:?}", used_by_this_id); let new_len = used_by_this_id.len(); assert!(new_len >= original_len, @@ -556,7 +556,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { { if let Some(edges) = self.dependencies.get(&item) { for item in edges { - debug!("enqueue {:?} into worklist", item); + trace!("enqueue {:?} into worklist", item); f(*item); } }