diff mbox

PR c++/51289 - ICE with alias template for bound template

Message ID m3aa7d26cu.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli Nov. 30, 2011, 11:32 a.m. UTC
Jason Merrill <jason@redhat.com> writes:

> On 11/29/2011 10:41 AM, Dodji Seketeli wrote:
>> +      cp_walk_tree (&DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
>> +		&find_parameter_packs_r,
>> +		    ppd, ppd->visited);
>
> I still don't think we want to walk the underlying type, since it
> isn't part of the syntactic form of the type in this context and
> therefore can't have relevant packs.

Here is an example of what I had in mind for keeping the walking of the
underlying type there:

    template <class ... T>
    struct S {};

    template<class ... T>
    using A = S<T>;//#1 <-- I think we should error here.

When we are in #1, in the process of building the template info for A,
push_template_decl_real_1 calls check_for_bare_parameter_packs, which
then call the code you are referring to.  If we don't walk the
underlying type there, we miss spotting the use the of the bare
parameter pack T.  Or am I miss-considering something?

FWIW, below is an updated patch with that example included.
Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/51289
	* cp-tree.h (TYPE_TEMPLATE_INFO): Rewrite this accessor macro to
	better support aliased types.
	(TYPE_ALIAS_P): Don't crash on TYPE_NAME nodes that are not
	TYPE_DECL.
	* pt.c (find_parameter_packs_r): Handle typedef variant types.

gcc/PR51289/gcc/testsuite/

	PR c++/51289
	* g++.dg/cpp0x/alias-decl-17.C: New test.
---
 gcc/cp/cp-tree.h                           |   28 ++++++++++++++++++----------
 gcc/cp/pt.c                                |   14 ++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C |   21 +++++++++++++++++++++
 3 files changed, 53 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C

Comments

Jason Merrill Nov. 30, 2011, 5:17 p.m. UTC | #1
On 11/30/2011 06:32 AM, Dodji Seketeli wrote:
> Here is an example of what I had in mind for keeping the walking of the
> underlying type there:
>
>      template<class ... T>
>      struct S {};
>
>      template<class ... T>
>      using A = S<T>;//#1<-- I think we should error here.

We certainly should; we do need to walk the pattern at the point of 
definition.  I meant that when we see a use of a typedef or alias 
template we don't need to walk the underlying type.

> When we are in #1, in the process of building the template info for A,
> push_template_decl_real_1 calls check_for_bare_parameter_packs, which
> then call the code you are referring to.  If we don't walk the
> underlying type there, we miss spotting the use the of the bare
> parameter pack T.  Or am I miss-considering something?

I guess let's check DECL_ORIGINAL_TYPE instead of TREE_TYPE for alias 
templates.

Jason
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3f4f408..b821928 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2553,6 +2553,7 @@  extern void decl_shadowed_for_var_insert (tree, tree);
 #define TYPE_ALIAS_P(NODE)			\
   (TYPE_P (NODE)				\
    && TYPE_NAME (NODE)				\
+   && TREE_CODE (TYPE_NAME (NODE)) == TYPE_DECL	\
    && TYPE_DECL_ALIAS_P (TYPE_NAME (NODE)))
 
 /* For a class type: if this structure has many fields, we'll sort them
@@ -2605,17 +2606,24 @@  extern void decl_shadowed_for_var_insert (tree, tree);
   (LANG_TYPE_CLASS_CHECK (BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK (NODE)) \
    ->template_info)
 
-/* Template information for an ENUMERAL_, RECORD_, or UNION_TYPE.  */
+/* Template information for an ENUMERAL_, RECORD_, UNION_TYPE, or
+   BOUND_TEMPLATE_TEMPLATE_PARM type.  Note that if NODE is a
+   specialization of an alias template, this accessor returns the
+   template info for the alias template, not the one (if any) for the
+   template of the underlying type.  */
 #define TYPE_TEMPLATE_INFO(NODE)					\
-  (TREE_CODE (NODE) == ENUMERAL_TYPE					\
-   ? ENUM_TEMPLATE_INFO (NODE) :					\
-   (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
-    ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE) :			\
-    ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))			\
-     ? CLASSTYPE_TEMPLATE_INFO (NODE)					\
-     : ((TYPE_NAME (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)))	\
-	? (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)))			\
-	: NULL_TREE))))
+  (TYPE_ALIAS_P (NODE)							\
+   ? ((TYPE_NAME (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)))	\
+      ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\
+      : NULL_TREE)							\
+   : ((TREE_CODE (NODE) == ENUMERAL_TYPE)				\
+      ? ENUM_TEMPLATE_INFO (NODE)					\
+      : ((TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM)		\
+	 ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE)			\
+	 : (CLASS_TYPE_P (NODE)						\
+	    ? CLASSTYPE_TEMPLATE_INFO (NODE)				\
+	    : NULL_TREE))))
+
 
 /* Set the template information for an ENUMERAL_, RECORD_, or
    UNION_TYPE to VAL.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4725080..5bc6f23 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2976,6 +2976,20 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
     (struct find_parameter_pack_data*)data;
   bool parameter_pack_p = false;
 
+  /* Handle type aliases/typedefs.  */
+  if (TYPE_P (t) && typedef_variant_p (t))
+    {
+      if (TYPE_TEMPLATE_INFO (t))
+	cp_walk_tree (&TYPE_TI_ARGS (t),
+		      &find_parameter_packs_r,
+		      ppd, ppd->visited);
+      cp_walk_tree (&DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
+		    &find_parameter_packs_r,
+		    ppd, ppd->visited);
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
   /* Identify whether this is a parameter pack or not.  */
   switch (TREE_CODE (t))
     {
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C
new file mode 100644
index 0000000..41b1c95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C
@@ -0,0 +1,21 @@ 
+// Origin PR c++/51289
+// { dg-options "-std=c++11" }
+
+template<typename a, template <typename, typename> class b>
+struct foo {
+  template <typename t>
+  using type = b<a, t>;
+  template <typename t>
+  b<a, t> funca() {}
+
+  template <typename t>
+  type<t> funcb() {}
+};
+
+// This is an additional test, to emit an error message when using
+// unexpanded parameter packs in an alias declaration.
+template <class ... T>
+struct S {};
+
+template<class ... T>
+using A = S<T>; // { dg-error "parameter packs not expanded" }