diff mbox

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

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

Commit Message

Dodji Seketeli Nov. 28, 2011, 4:54 p.m. UTC
Hello,

Consider this example:

    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() {}//#1
    };

In #1, when lookup_template_class_1 builds the type of type<t> we hit
a kind of plumbing issue; near the end of the the 'if' below,

      if (arg_depth == 1 && parm_depth > 1)
	{
	  /* We've been given an incomplete set of template arguments.
	     For example, given:

	       template <class T> struct S1 {
		 template <class U> struct S2 {};
		 template <class U> struct S2<U*> {};
		};

	     we will be called with an ARGLIST of `U*', but the
	     TEMPLATE will be `template <class T> template
	     <class U> struct S1<T>::S2'.  We must fill in the missing
	     arguments.  */
	  arglist
	    = add_outermost_template_args (TYPE_TI_ARGS (TREE_TYPE (templ)),
					   arglist);
	  arg_depth = TMPL_ARGS_DEPTH (arglist);
	}

we try to get the arguments of the alias template type using
TYPE_TI_ARGS, and that fails because TREE_TYPE (templ) is a
BOUND_TEMPLATE_TEMPLATE_PARM, and TEMPLATE_TYPE_INFO behaves
incorrectly for BOUND_TEMPLATE_TEMPLATE_PARM nodes when they represent
the underlying type of an aliased type.  We wrongly poke at the
arguments of the underlying BOUND_TEMPLATE_TEMPLATE_PARM instead.

Thus patch below changes the TEMPLATE_TYPE_INFO accessor.

I also had to adjust find_parameter_packs_r to always get the template
info from the underlying type when faced with type aliases.
Otherwise, it can wrongly attempt to poke at arguments of the template
aliases even when these are not yet ready; this can happen e.g when
check_for_bare_parameter_packs is called from push_template_decl_real
before the template information for the alias template specialization
is in place.  Also I think we don't risk missing any parameter pack by
only considering the underlying type in the case of alias template
specializations.

Bootstrapped and tested against 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.
	* pt.c ():

gcc/PR51289/gcc/testsuite/

	PR c++/51289
	* g++.dg/cpp0x/alias-decl-17.C: New test.
---
 gcc/cp/cp-tree.h                           |   27 +++++++++++++++++----------
 gcc/cp/pt.c                                |    6 ++++--
 gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C |   13 +++++++++++++
 3 files changed, 34 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C

Comments

Jason Merrill Nov. 28, 2011, 10:06 p.m. UTC | #1
On 11/28/2011 11:54 AM, Dodji Seketeli wrote:
> @@ -3028,10 +3028,12 @@ find_parameter_packs_r (tree*tp, int *walk_subtrees, void*  data)
>
>       case BOUND_TEMPLATE_TEMPLATE_PARM:
>         /* Check the template itself.  */
> -      cp_walk_tree (&TREE_TYPE (TYPE_TI_TEMPLATE (t)),
> +      cp_walk_tree (&TREE_TYPE (TI_TEMPLATE
> +				(TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t))),
>   		&find_parameter_packs_r, ppd, ppd->visited);
>         /* Check the template arguments.  */
> -      cp_walk_tree (&TYPE_TI_ARGS (t),&find_parameter_packs_r, ppd,
> +      cp_walk_tree (&TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t)),
> +		&find_parameter_packs_r, ppd,
>   		    ppd->visited);
>         *walk_subtrees = 0;
>         return NULL_TREE;

Instead of this change, I think we should handle typedefs/aliases at the 
top of the function.  We shouldn't need to look into the underlying type 
for packs.

Jason
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3f4f408..dece84e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2605,17 +2605,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..2edf9e9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3028,10 +3028,12 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
 
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       /* Check the template itself.  */
-      cp_walk_tree (&TREE_TYPE (TYPE_TI_TEMPLATE (t)), 
+      cp_walk_tree (&TREE_TYPE (TI_TEMPLATE
+				(TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t))),
 		    &find_parameter_packs_r, ppd, ppd->visited);
       /* Check the template arguments.  */
-      cp_walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd, 
+      cp_walk_tree (&TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t)),
+		    &find_parameter_packs_r, ppd,
 		    ppd->visited);
       *walk_subtrees = 0;
       return NULL_TREE;
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..a7b2d37
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-17.C
@@ -0,0 +1,13 @@ 
+// 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() {}
+};