diff options
Diffstat (limited to 'src/ir/analysis/template_params.rs')
-rw-r--r-- | src/ir/analysis/template_params.rs | 272 |
1 files changed, 156 insertions, 116 deletions
diff --git a/src/ir/analysis/template_params.rs b/src/ir/analysis/template_params.rs index 44878d9e..caaa8f30 100644 --- a/src/ir/analysis/template_params.rs +++ b/src/ir/analysis/template_params.rs @@ -147,7 +147,8 @@ use std::collections::{HashMap, HashSet}; /// documentation for details. #[derive(Debug, Clone)] pub struct UsedTemplateParameters<'ctx, 'gen> - where 'gen: 'ctx, +where + 'gen: 'ctx, { ctx: &'ctx BindgenContext<'gen>, @@ -208,11 +209,15 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { 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") + .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`") + .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 @@ -220,14 +225,19 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { /// 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, - this_id: ItemId, - used_by_this_id: &mut ItemSet, - instantiation: &TemplateInstantiation) { - trace!(" instantiation of blacklisted template, uses all template \ - arguments"); - - let args = instantiation.template_arguments() + fn constrain_instantiation_of_blacklisted_template( + &self, + this_id: ItemId, + used_by_this_id: &mut ItemSet, + instantiation: &TemplateInstantiation, + ) { + trace!( + " instantiation of blacklisted template, uses all template \ + arguments" + ); + + let args = instantiation + .template_arguments() .into_iter() .map(|a| { a.into_resolver() @@ -238,12 +248,15 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { }) .filter(|a| *a != this_id) .flat_map(|a| { - self.used.get(&a) + self.used + .get(&a) .expect("Should have a used entry for the template arg") .as_ref() - .expect("Because a != this_id, and all used template \ + .expect( + "Because a != this_id, and all used template \ param sets other than this_id's are `Some`, \ - a's used template param set should be `Some`") + a's used template param set should be `Some`", + ) .iter() .cloned() }); @@ -253,17 +266,18 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { /// A template instantiation's concrete template argument is only used if /// the template definition uses the corresponding template parameter. - fn constrain_instantiation(&self, - this_id: ItemId, - used_by_this_id: &mut ItemSet, - instantiation: &TemplateInstantiation) { + fn constrain_instantiation( + &self, + this_id: ItemId, + 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 params = decl.self_template_params(self.ctx).unwrap_or(vec![]); debug_assert!(this_id != instantiation.template_definition()); let used_by_def = self.used @@ -275,10 +289,12 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { instantiation itself"); for (arg, param) in args.iter().zip(params.iter()) { - trace!(" instantiation's argument {:?} is used if definition's \ + trace!( + " instantiation's argument {:?} is used if definition's \ parameter {:?} is used", - arg, - param); + arg, + param + ); if used_by_def.contains(param) { trace!(" param is used by template definition"); @@ -297,10 +313,12 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { .get(&arg) .expect("Should have a used entry for the template arg") .as_ref() - .expect("Because arg != this_id, and all used template \ + .expect( + "Because arg != this_id, and all used template \ param sets other than this_id's are `Some`, \ arg's used template param set should be \ - `Some`") + `Some`", + ) .iter() .cloned(); used_by_this_id.extend(used_by_arg); @@ -313,31 +331,39 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { 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. - if sub_id == item.id() || !Self::consider_edge(edge_kind) { - return; - } + 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. + if sub_id == item.id() || !Self::consider_edge(edge_kind) { + return; + } - let used_by_sub_id = self.used - .get(&sub_id) - .expect("Should have a used set for the sub_id successor") - .as_ref() - .expect("Because sub_id != id, and all used template \ + let used_by_sub_id = self.used + .get(&sub_id) + .expect("Should have a used set for the sub_id successor") + .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(); + `Some`", + ) + .iter() + .cloned(); - trace!(" union with {:?}'s usage: {:?}", - sub_id, - used_by_sub_id.clone().collect::<Vec<_>>()); + trace!( + " union with {:?}'s usage: {:?}", + sub_id, + used_by_sub_id.clone().collect::<Vec<_>>() + ); - used_by_this_id.extend(used_by_sub_id); - }, &()); + used_by_this_id.extend(used_by_sub_id); + }, + &(), + ); } } @@ -346,22 +372,20 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { type Extra = &'ctx BindgenContext<'gen>; type Output = HashMap<ItemId, ItemSet>; - fn new(ctx: &'ctx BindgenContext<'gen>) - -> UsedTemplateParameters<'ctx, 'gen> { + fn new( + ctx: &'ctx BindgenContext<'gen>, + ) -> UsedTemplateParameters<'ctx, 'gen> { let mut used = HashMap::new(); let mut dependencies = HashMap::new(); - let whitelisted_items: HashSet<_> = ctx.whitelisted_items() - .iter() - .cloned() - .collect(); + let whitelisted_items: HashSet<_> = + ctx.whitelisted_items().iter().cloned().collect(); - let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items.iter() + let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items + .iter() .cloned() .flat_map(|i| { let mut reachable = vec![i]; - i.trace(ctx, &mut |s, _| { - reachable.push(s); - }, &()); + i.trace(ctx, &mut |s, _| { reachable.push(s); }, &()); reachable }) .collect(); @@ -373,53 +397,54 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { { // We reverse our natural IR graph edges to find dependencies // between nodes. - item.trace(ctx, &mut |sub_item: ItemId, _| { - used.entry(sub_item).or_insert(Some(ItemSet::new())); - dependencies.entry(sub_item) - .or_insert(vec![]) - .push(item); - }, &()); + item.trace( + ctx, + &mut |sub_item: ItemId, _| { + used.entry(sub_item).or_insert(Some(ItemSet::new())); + dependencies.entry(sub_item).or_insert(vec![]).push( + item, + ); + }, + &(), + ); } // Additionally, whether a template instantiation's template // arguments are used depends on whether the template declaration's // generic template parameters are used. - ctx.resolve_item(item) - .as_type() - .map(|ty| match ty.kind() { - &TypeKind::TemplateInstantiation(ref inst) => { - let decl = ctx.resolve_type(inst.template_definition()); - let args = inst.template_arguments(); - - // Although template definitions should always have - // template parameters, there is a single exception: - // opaque templates. Hence the unwrap_or. - let params = decl.self_template_params(ctx) - .unwrap_or(vec![]); - - for (arg, param) in args.iter().zip(params.iter()) { - let arg = arg.into_resolver() - .through_type_aliases() - .through_type_refs() - .resolve(ctx) - .id(); - - let param = param.into_resolver() - .through_type_aliases() - .through_type_refs() - .resolve(ctx) - .id(); - - used.entry(arg).or_insert(Some(ItemSet::new())); - used.entry(param).or_insert(Some(ItemSet::new())); - - dependencies.entry(arg) - .or_insert(vec![]) - .push(param); - } + ctx.resolve_item(item).as_type().map(|ty| match ty.kind() { + &TypeKind::TemplateInstantiation(ref inst) => { + let decl = ctx.resolve_type(inst.template_definition()); + let args = inst.template_arguments(); + + // Although template definitions should always have + // template parameters, there is a single exception: + // opaque templates. Hence the unwrap_or. + let params = + decl.self_template_params(ctx).unwrap_or(vec![]); + + for (arg, param) in args.iter().zip(params.iter()) { + let arg = arg.into_resolver() + .through_type_aliases() + .through_type_refs() + .resolve(ctx) + .id(); + + let param = param + .into_resolver() + .through_type_aliases() + .through_type_refs() + .resolve(ctx) + .id(); + + used.entry(arg).or_insert(Some(ItemSet::new())); + used.entry(param).or_insert(Some(ItemSet::new())); + + dependencies.entry(arg).or_insert(vec![]).push(param); } - _ => {} - }); + } + _ => {} + }); } if cfg!(feature = "testing_only_extra_assertions") { @@ -436,10 +461,14 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { for item in whitelisted_items.iter() { extra_assert!(used.contains_key(item)); extra_assert!(dependencies.contains_key(item)); - item.trace(ctx, &mut |sub_item, _| { - extra_assert!(used.contains_key(&sub_item)); - extra_assert!(dependencies.contains_key(&sub_item)); - }, &()) + item.trace( + ctx, + &mut |sub_item, _| { + extra_assert!(used.contains_key(&sub_item)); + extra_assert!(dependencies.contains_key(&sub_item)); + }, + &(), + ) } } @@ -460,9 +489,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { .cloned() .flat_map(|i| { let mut reachable = vec![i]; - i.trace(self.ctx, &mut |s, _| { - reachable.push(s); - }, &()); + i.trace(self.ctx, &mut |s, _| { reachable.push(s); }, &()); reachable }) .collect() @@ -488,19 +515,28 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { let ty_kind = item.as_type().map(|ty| ty.kind()); match ty_kind { // Named template type parameters trivially use themselves. - Some(&TypeKind::Named) => { + Some(&TypeKind::TypeParam) => { trace!(" named type, trivially uses itself"); used_by_this_id.insert(id); } // Template instantiations only use their template arguments if the // template definition uses the corresponding template parameter. Some(&TypeKind::TemplateInstantiation(ref inst)) => { - if self.whitelisted_items.contains(&inst.template_definition()) { - self.constrain_instantiation(id, &mut used_by_this_id, inst); + if self.whitelisted_items.contains( + &inst.template_definition(), + ) + { + self.constrain_instantiation( + id, + &mut used_by_this_id, + inst, + ); } else { - self.constrain_instantiation_of_blacklisted_template(id, - &mut used_by_this_id, - inst); + self.constrain_instantiation_of_blacklisted_template( + id, + &mut used_by_this_id, + inst, + ); } } // Otherwise, add the union of each of its referent item's template @@ -511,9 +547,11 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { 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 -- \ - if it doesn't hold, the analysis might never terminate!"); + assert!( + new_len >= original_len, + "This is the property that ensures this function is monotone -- \ + if it doesn't hold, the analysis might never terminate!" + ); // Put the set back in the hash map and restore our invariant. debug_assert!(self.used[&id].is_none()); @@ -528,7 +566,8 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { } fn each_depending_on<F>(&self, item: ItemId, mut f: F) - where F: FnMut(ItemId), + where + F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&item) { for item in edges { @@ -542,7 +581,8 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { impl<'ctx, 'gen> From<UsedTemplateParameters<'ctx, 'gen>> for HashMap<ItemId, ItemSet> { fn from(used_templ_params: UsedTemplateParameters<'ctx, 'gen>) -> Self { - used_templ_params.used + used_templ_params + .used .into_iter() .map(|(k, v)| (k, v.unwrap())) .collect() |