public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Nested non-type template parameter packs using outer template parameter packs (PR c++/35022)
@ 2008-02-15 17:41 Doug Gregor
  2008-03-25 19:37 ` Jason Merrill
  0 siblings, 1 reply; 3+ messages in thread
From: Doug Gregor @ 2008-02-15 17:41 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 2178 bytes --]

This patch fixes PR c++/35022, a regression involving non-type
template parameter packs whose type involves template parameter packs
from an outer level of templates. The basic problem shown in PR
c++/35022 is that we weren't properly dealing with
tsubst_pack_expansion when it returns a pack expansion, as it does
when we're substituting into a nested template. This patch fixes this
problem in two contexts: when coercing template arguments to a
non-type template parameter pack  (the ICE from the PR) and also when
dealing with the "sizeof...(X)" form of SIZEOF_EXPR.
Also, the actual PR was an ice-on-invalid-code, where adding an
ellipsis makes the code ill-formed. Unfortunately, that illuminated an
error in the parsing logic, where we weren't properly parsing an
unnamed non-type template parameter pack. The parser tweaks in this
patch fix that problem.

The astute reviewer will note that there are 3 xfails in this new test
case. These are examples that I believe should be well-formed, but (1)
it's not entirely clear that the C++0x working paper agrees with me,
(2) the results of this test case will change anyway if N2488 goes
through in two weeks, and (3) I don't have a fix, but the probable fix
would affect too much C++98 code for me to propose at this stage of
GCC development.

Tested i686-pc-linux-gnu, fixes a regression; okay for 4.3?

  - Doug

2008-02-15  Douglas Gregor  <doug.gregor@gmail.com>

	PR c++/35022
	* pt.c (coerce_template_parameter_pack): Cope with
	tsubst_pack_expansion returning a pack expansion (as occurs when
	substituting into a nested template).
	(tsubst_copy) <case SIZEOF_EXPR>: Cope with tsubst_pack_expansion
	returning a pack expansion, or a TREE_VEC ending in a pack
	expansion, both of which can occur when substituting into a nested
	template.
	(tsubst_copy_and_build) <case SIZEOF_EXPR>: When we're
	instantiating the sizeof...(X) form, make tsubst_copy do the
	work.
	* parser.c (cp_parser_template_parameter): Deal with unnamed
	non-type template parameter packs identified by pack expansions in
	the parameter type.
	
2008-02-15  Douglas Gregor  <doug.gregor@gmail.com>

	PR c++/35022
	* g++.dg/cpp0x/vt-35022.C: New.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: variadic-ttp.patch --]
[-- Type: text/x-patch; name=variadic-ttp.patch, Size: 6982 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 132340)
+++ cp/pt.c	(working copy)
@@ -5045,8 +5045,19 @@ coerce_template_parameter_pack (tree par
       if (packed_types == error_mark_node)
         return error_mark_node;
 
+      /* If the type of the non-type template parameter pack includes
+	 a template parameter pack from an outer template, we can end
+	 up with a pack expansion as the result of
+	 tsubst_pack_expansion. In this case, just pretend that there
+	 are no "packed types".  That way, we'll just compare each of
+	 the template arguments against this same template parameter
+	 type.  */
+      if (PACK_EXPANSION_P (packed_types))
+	packed_types = NULL_TREE;
+
       /* Check that we have the right number of arguments.  */
       if (arg_idx < nargs
+	  && packed_types
           && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx))
           && nargs - arg_idx != TREE_VEC_LENGTH (packed_types))
         {
@@ -5063,6 +5074,7 @@ coerce_template_parameter_pack (tree par
          template parameter pack are, in fact, valid for non-type
          template parameters.  */
       if (arg_idx < nargs 
+	  && packed_types
           && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx)))
         {
           int j, len = TREE_VEC_LENGTH (packed_types);
@@ -9836,9 +9848,29 @@ tsubst_copy (tree t, tree args, tsubst_f
           /* We only want to compute the number of arguments.  */
           tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
                                                 complain, in_decl);
+	  int len;
+
+	  if (TREE_CODE (expanded) == TREE_VEC)
+	    len = TREE_VEC_LENGTH (expanded);
+
 	  if (expanded == error_mark_node)
 	    return error_mark_node;
-          return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+	  else if (PACK_EXPANSION_P (expanded)
+		   || (TREE_CODE (expanded) == TREE_VEC
+		       && len > 0
+		       && PACK_EXPANSION_P (TREE_VEC_ELT (expanded, len-1))))
+	    {
+	      if (TREE_CODE (expanded) == TREE_VEC)
+		expanded = TREE_VEC_ELT (expanded, len - 1);
+
+	      if (TYPE_P (expanded))
+		return cxx_sizeof_or_alignof_type (expanded, SIZEOF_EXPR, 
+						   true);
+	      else
+		return cxx_sizeof_or_alignof_expr (expanded, SIZEOF_EXPR);
+	    }
+	  else
+	    return build_int_cst (size_type_node, len);
         }
       /* Fall through */
 
@@ -10834,14 +10866,7 @@ tsubst_copy_and_build (tree t,
 
     case SIZEOF_EXPR:
       if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
-        {
-          /* We only want to compute the number of arguments.  */
-          tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
-                                                complain, in_decl);
-	  if (expanded == error_mark_node)
-	    return error_mark_node;
-          return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
-        }
+	return tsubst_copy (t, args, complain, in_decl);
       /* Fall through */
       
     case ALIGNOF_EXPR:
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 132340)
+++ cp/parser.c	(working copy)
@@ -9401,29 +9401,41 @@ cp_parser_template_parameter (cp_parser*
       maybe_warn_variadic_templates ();
       
       *is_parameter_pack = true;
+    }
+  /* We might end up with a pack expansion as the type of the non-type
+     template parameter, in which case this is a non-type template
+     parameter pack.  */
+  else if (parameter_declarator
+	   && parameter_declarator->decl_specifiers.type
+	   && PACK_EXPANSION_P (parameter_declarator->decl_specifiers.type))
+    {
+      *is_parameter_pack = true;
+      parameter_declarator->decl_specifiers.type = 
+	PACK_EXPANSION_PATTERN (parameter_declarator->decl_specifiers.type);
+    }
 
+  if (*is_parameter_pack && cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+    {
       /* Parameter packs cannot have default arguments.  However, a
 	 user may try to do so, so we'll parse them and give an
 	 appropriate diagnostic here.  */
-      if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
-	{
-	  /* Consume the `='.  */
-	  cp_lexer_consume_token (parser->lexer);
 
-	  /* Find the name of the parameter pack.  */     
-	  id_declarator = parameter_declarator->declarator;
-	  while (id_declarator && id_declarator->kind != cdk_id)
-	    id_declarator = id_declarator->declarator;
-	  
-	  if (id_declarator && id_declarator->kind == cdk_id)
-	    error ("template parameter pack %qD cannot have a default argument",
-		   id_declarator->u.id.unqualified_name);
-	  else
-	    error ("template parameter pack cannot have a default argument");
-
-          /* Parse the default argument, but throw away the result.  */
-          cp_parser_default_argument (parser, /*template_parm_p=*/true);
-	}
+      /* Consume the `='.  */
+      cp_lexer_consume_token (parser->lexer);
+      
+      /* Find the name of the parameter pack.  */     
+      id_declarator = parameter_declarator->declarator;
+      while (id_declarator && id_declarator->kind != cdk_id)
+	id_declarator = id_declarator->declarator;
+      
+      if (id_declarator && id_declarator->kind == cdk_id)
+	error ("template parameter pack %qD cannot have a default argument",
+	       id_declarator->u.id.unqualified_name);
+      else
+	error ("template parameter pack cannot have a default argument");
+      
+      /* Parse the default argument, but throw away the result.  */
+      cp_parser_default_argument (parser, /*template_parm_p=*/true);
     }
 
   parm = grokdeclarator (parameter_declarator->declarator,
Index: testsuite/g++.dg/cpp0x/vt-35022.C
===================================================================
--- testsuite/g++.dg/cpp0x/vt-35022.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/vt-35022.C	(revision 0)
@@ -0,0 +1,52 @@
+// { dg-options "-std=c++0x" }
+template<typename... T, template<T...p> class X> void f1(X<0>);
+
+template<int> class X1 { };
+template<int...> class X2 { };
+
+void g1()
+{
+  X1<0> x1;
+  f1<int>(x1); // { dg-bogus "no matching" "" { xfail *-*-* } 10 }
+
+  X2<0> x2;
+  f1<int>(x2); // { dg-error "no matching" }
+}
+
+template<typename... T, template<T> class X> void f2(X<0>); // { dg-error "not expanded|T" }
+
+void g2()
+{
+  X1<0> x1;
+  f2<int>(x1); // { dg-bogus "no matching"  "" { xfail *-*-* } 21 }
+
+  X2<0> x2;
+  f2<int>(x2); // { dg-error "no matching" }
+}
+
+template<typename... T, template<T...> class X> void f3(X<0>);
+
+void g3()
+{
+  X1<0> x1;
+  f3<int>(x1); // { dg-bogus "no matching"  "" { xfail *-*-* } 32 }
+
+  X2<0> x2;
+  f3<int>(x2); // { dg-error "no matching" }
+}
+
+
+template<int N> struct Int2Type { };
+
+template<typename... T>
+struct Outer {
+  template<typename... U>
+  void foo(Int2Type<sizeof...(T)>, Int2Type<sizeof...(U)>);
+};
+
+
+Outer<short, int, long> outer;
+
+void g4() {
+  outer.foo<float, double>(Int2Type<3>(), Int2Type<2>());
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-03-27 14:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-15 17:41 [C++ PATCH] Nested non-type template parameter packs using outer template parameter packs (PR c++/35022) Doug Gregor
2008-03-25 19:37 ` Jason Merrill
2008-03-27 15:19   ` Doug Gregor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).