On 2013-11-10 23:21, Jason Merrill wrote:
On 11/10/2013 02:39 PM, Adam Butcher wrote:
I assumed that tsubst simply doesn't do anything with a
null tree substitution (i.e. it is an identity op).

Substituting NULL_TREE for a template parameter gives a template
parameter with a reduced level; this happens during partial
instantiation.

Ah, OK.

Since we are tsubsting the declaration here and we only want to adjust
the template parameter types themselves at their declaration is this
really necessary? I've no problem with implementing this if it truly is
necessary but I don't want to add unnecessary cycles if not.

The difference between setting copying a pointer to a vec versus
setting it to null seems completely negligible to me.

Sure. I was more concerned with allocating vecs for each outer list and copying the parms over versus allocating a 'null' placeholder list for each level which we're not concerned about. No worries though, I've proceeded with your suggestion below.

I think it is necessary in case the function parameter type involves
template parameters from the enclosing context as well as implicit
template parameters.

One other thing, by 'copy' I take it you mean copy the tree vecs of the
enclosing levels only, not also the types within them.

Yes, using add_outermost_template_args.

I have done this (diff -w -b follows). The route to this seems even more costly though; current_template_parms needs to first be converted to a vec by current_template_args() then the last nesting level is thrown away and replaced with the one we're working on. It's all working but I'm wondering whether a custom loop here would be better.

And I also assume that I'll need to set the currently unset types in the inner
level also?

Can you have explicit template parameters at the same level as the
implicit ones?

Yes.

If so, then their places in the vec will need to be
set appropriately in case they are used in the function parameter
type.

OK. I had testcases that appeared to pass OK with the previous NULL_TREE tsubst but maybe I wasn't checking something (perhaps a combination of an explicit template parm type and an auto in a single parm).

End result is that everything looks OK though so we might be able to get the C++14 lambda support marked as "in 4.9" soon hopefully.

Cheers,
Adam
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 360d8a3..69c7688 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21641,6 +21641,10 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
   current = INNERMOST_TEMPLATE_PARMS (current);
   tree replacement = make_tree_vec (TREE_VEC_LENGTH (current));
 
+  for (int i = 0; i < start_idx; ++i)
+    TREE_VEC_ELT (replacement, i)
+      = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i)));
+
   for (int i = start_idx; i < end_idx; ++i)
     {
       /* Create a distinct parameter pack type from the current parm and add it
@@ -21662,18 +21666,15 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
       TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);
     }
 
+  for (int i = end_idx, e = TREE_VEC_LENGTH (current); i < e; ++i)
+    TREE_VEC_ELT (replacement, i)
+      = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i)));
+
   if (depth > 1)
-    {
     /* Build up a tree vec of empty tree vecs up to the inner substitution
        args built above.  */
-
-      tree inner = replacement;
-      replacement = make_tree_vec (depth);
-      int last = depth - 1;
-      for (int i = 0; i < last; ++i)
-	TREE_VEC_ELT (replacement, i) = make_tree_vec (0);
-      TREE_VEC_ELT (replacement, last) = inner;
-    }
+    replacement = add_outermost_template_args (current_template_args (),
+					       replacement);
 
   return tsubst (parm, replacement, tf_none, NULL_TREE);
 }

Reply via email to