Hello,
I have conflated the handling of two PRs here, because I think they
are related.
Consider this short example that illustrates the issue of PR
c++/51239:
struct S {};
templatetypename T, typename...
using head = T;
templatetypename... Ts
using x = headTs...;//#1
In #1, we want to be able to represent 'headTs...', in such a way
that the Ts... argument is not substituted for the parameter of f the
head template. Because the pack expansion Ts... means that we don't
yet have the proper arguments to apply to the head template. Later
when we have those arguments, for instance:
xint, char i0;
we can proceed with substituting the argument pack [int, char] into
the pack expansion Ts... to get a set of argument {int, char} that
we'll apply to the head template, to get int.
To date we don't have such an unbound alias template specialization
representation, because we leverage on the fact that head is an
alias template to substitute its arguments into its underlying type
directly. Doing that in the present case (the argument being a pack
expansion) just wreaks havoc as the PR can attest.
After talking with you offline, we settled on using the existing
BOUND_TEMPLATE_TEMPLATE_PARM tree to represent this new construct.
The alias template and its unbound arguments are stored in the
TYPE_TEMPLATE_INFO of the tree and its TYPE_NAME has the
TYPE_DECL_ALIAS_P flag set.
So now, during the process of building a template specialization,
coerce_template_parms detects that we don't have all the arguments yet
- that is, when one of the arguments is a pack expansion. In that
case lookup_template_class_1, if the template is an alias template,
builds an unbound alias template specialization and returns it.
We also support substituting for an unbound alias template
specialization.
The problem in PR c++/51180 is that sometimes coerce_template_parms
won't let us build a type fooT... if the template foo has more
than one parameter and no parameter pack. We then end up in the if
below, and error out:
if ((nargs nparms !variadic_p)
|| (nargs nparms - variadic_p
require_all_args
(!use_default_args
|| (TREE_VEC_ELT (parms, nargs) != error_mark_node
!TREE_PURPOSE (TREE_VEC_ELT (parms, nargs))
{
So the patch below tries to fix that as well.
Incidentally, I noticed that the test g++.dg/cpp0x/alias-decl-15.C
should actually be considered valid. I wrongly thought otherwise at
that time. I have thus adjusted that test case accordingly.
Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.
gcc/cp/
PR c++/51239
PR c++/51180
* cp-tree.h (UNBOUND_ALIAS_TEMPLATE_P): New
predicate.
* pt.c (build_unbound_alias_template): New.
(coerce_template_parms): Take a new out parameter flag about if
the actual number of arguments is unknown. Make the template
unbound if one of its arguments is a pack expansion.
(lookup_template_class_1): Adjust for new argument to
coerce_template_parms. Build an unbound alias template if the
number of arguments is not known yet.
(tsubst)BOUND_TEMPLATE_TEMPLATE_PARM: Handle unbound alias
templates.
(fn_type_unification, get_bindings, most_specialized_class):
Adjust for new argument to coerce_template_parms.
gcc/testsuite/
PR c++/51239
PR c++/51180
* g++.dg/cpp0x/alias-decl-18.C: New test.
* g++.dg/cpp0x/alias-decl-19.C: Likewise.
* g++.dg/cpp0x/alias-decl-15.C: This was wrongly expected
to fail before. Adjust accordingly.
---
gcc/cp/cp-tree.h | 10 +++
gcc/cp/pt.c| 108 +---
gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C | 10 ++--
gcc/testsuite/g++.dg/cpp0x/alias-decl-18.C | 29
gcc/testsuite/g++.dg/cpp0x/alias-decl-19.C | 19 +
5 files changed, 161 insertions(+), 15 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-18.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-19.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3f4f408..0dcebd6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3662,6 +3662,16 @@ more_aggr_init_expr_args_p (const
aggr_init_expr_arg_iterator *iter)
(DECL_TYPE_TEMPLATE_P (NODE) \
!DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (NODE)))
+/* Nonzero for a node representing an alias template specialization in
+ which the arguments are not yet applied to the alias template.
+ This is used in cases where the arguments are not all fully known
+ yet, and can be applied later when they are. */
+#define UNBOUND_ALIAS_TEMPLATE_P(NODE) \
+ ((NODE) \
+TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM \
+DECL_ALIAS_TEMPLATE_P