summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-04-14 15:51:54 -0700
committerNick Fitzgerald <fitzgen@gmail.com>2017-04-17 09:30:05 -0700
commit568b01114517a02e098c2bb39ca504dabfcc55c7 (patch)
tree45d498ec45210fa54a7ee184d1869cb60b6fe91a
parenta36c09baed79bfb4368df5c6e537f4f485653646 (diff)
Ensure that every item we `constrain` has a set of used template parameters
This is a follow up to c8a206a, and the support for blacklisting in the named template parameter usage analysis. This ensures that ever item we ever call `constrain` on has an entry in `used` for the set of template parameters it uses. Additionally, it adds extra assertions to enforce the invariant. We cannot completely avoid analyzing blacklisted items because we want to consider all of a blacklisted template's parameters as used. This is why we ensure that blacklisted items have a used template parameter set rather than ensuring that blacklisted items never end up in the worklist.
-rw-r--r--src/ir/named.rs31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/ir/named.rs b/src/ir/named.rs
index 1af98a26..2bab5e4e 100644
--- a/src/ir/named.rs
+++ b/src/ir/named.rs
@@ -322,12 +322,14 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
for item in whitelisted_items.iter().cloned() {
dependencies.entry(item).or_insert(vec![]);
- used.insert(item, Some(ItemSet::new()));
+ used.entry(item).or_insert(Some(ItemSet::new()));
{
// We reverse our natural IR graph edges to find dependencies
// between nodes.
item.trace(ctx, &mut |sub_item, _| {
+ used.entry(sub_item).or_insert(Some(ItemSet::new()));
+
// We won't be generating code for items that aren't
// whitelisted, so don't bother keeping track of their
// template parameters. But isn't whitelisting the
@@ -353,12 +355,17 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
&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()) {
+ used.entry(*arg).or_insert(Some(ItemSet::new()));
+ used.entry(*param).or_insert(Some(ItemSet::new()));
+
dependencies.entry(*arg)
.or_insert(vec![])
.push(*param);
@@ -368,6 +375,28 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
});
}
+ if cfg!(feature = "testing_only_extra_assertions") {
+ // Invariant: The `used` map has an entry for every whitelisted
+ // item, as well as all explicitly blacklisted items that are
+ // reachable from whitelisted items.
+ //
+ // (This is so that every item we call `constrain` on is guaranteed
+ // to have a set of template parameters, and we can allow
+ // blacklisted templates to use all of their parameters).
+ for item in whitelisted_items.iter() {
+ extra_assert!(used.contains_key(item));
+ item.trace(ctx, &mut |sub_item, _| {
+ extra_assert!(used.contains_key(&sub_item));
+ }, &())
+ }
+
+ // Invariant: the `dependencies` map has an entry for every
+ // whitelisted item.
+ for item in whitelisted_items.iter() {
+ extra_assert!(dependencies.contains_key(item));
+ }
+ }
+
UsedTemplateParameters {
ctx: ctx,
used: used,