public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* PING: C++0x variadic templates fixes
@ 2007-07-25 19:40 Doug Gregor
  2007-08-17 19:29 ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Doug Gregor @ 2007-07-25 19:40 UTC (permalink / raw)
  To: GCC Patches

These patches fix a few PRs against logged against variadic templates:

  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00365.html
  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00170.html

Okay for mainline?

  - Doug

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

* Re: PING: C++0x variadic templates fixes
  2007-07-25 19:40 PING: C++0x variadic templates fixes Doug Gregor
@ 2007-08-17 19:29 ` Jason Merrill
  2007-08-31 19:42   ` Doug Gregor
  2007-10-26 18:24   ` Doug Gregor
  0 siblings, 2 replies; 5+ messages in thread
From: Jason Merrill @ 2007-08-17 19:29 UTC (permalink / raw)
  To: Doug Gregor; +Cc: GCC Patches

Doug Gregor wrote:
> These patches fix a few PRs against logged against variadic templates:
> 
>  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00170.html

> +			  init = build_default_init (TREE_TYPE (decl), 
> +						     integer_one_node);

Why integer_one_node?  NULL_TREE seems more appropriate.

 >  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00365.html

> 	(tsubst_pack_expansion): We our substitution of a parameter pack
> 	is a "trivial" substitution of itself, just substitute into the

We?

Your changes to convert_template_argument cause check_arg to be used 
much more.  Do we still need the distinction between arg and check_arg?

> +          if ((TYPE_P (pattern) && same_type_p (pattern, parm_pack))
> +              || (!TYPE_P (pattern) && cp_tree_equal (parm_pack, pattern)))
> +            /* The argument pack that the parameter maps to is just an
> +               expansion of the parameter itself, such as one would
> +               find in the implicit typedef of a class inside the
> +               class itself.  Consider this parameter "unsubstituted",
> +               so that we will maintain the outer pack expansion.  */

> +                /* We can get a pack expansion here when we are
> +                   instantiating a member template and ARG is a pack
> +                   expansion from the outer template.  */
> +                if (PACK_EXPANSION_P (arg))
> +                  arg = PACK_EXPANSION_PATTERN (arg);

Can you give me an example of how these two situations come up?  It's 
not clear to me how the testcases relate to the fixes.

Jason

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

* Re: PING: C++0x variadic templates fixes
  2007-08-17 19:29 ` Jason Merrill
@ 2007-08-31 19:42   ` Doug Gregor
  2007-10-26 18:24   ` Doug Gregor
  1 sibling, 0 replies; 5+ messages in thread
From: Doug Gregor @ 2007-08-31 19:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On 8/17/07, Jason Merrill <jason@redhat.com> wrote:
> Doug Gregor wrote:
> > These patches fix a few PRs against logged against variadic templates:
> >
> >  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00170.html
>
> > +                       init = build_default_init (TREE_TYPE (decl),
> > +                                                  integer_one_node);
>
> Why integer_one_node?  NULL_TREE seems more appropriate.

Hmmm, you're right. Thanks!

  - Doug

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

* Re: PING: C++0x variadic templates fixes
  2007-08-17 19:29 ` Jason Merrill
  2007-08-31 19:42   ` Doug Gregor
@ 2007-10-26 18:24   ` Doug Gregor
  2007-10-30  7:12     ` Jason Merrill
  1 sibling, 1 reply; 5+ messages in thread
From: Doug Gregor @ 2007-10-26 18:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

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

On 8/17/07, Jason Merrill <jason@redhat.com> wrote:
>  >  http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00365.html
>
> >       (tsubst_pack_expansion): We our substitution of a parameter pack
> >       is a "trivial" substitution of itself, just substitute into the
>
> We?

Heh, "When" was intended there...

> Your changes to convert_template_argument cause check_arg to be used
> much more.  Do we still need the distinction between arg and check_arg?

We need to keep the original argument around in some cases, for error
messages and to safely back out of some error conditions. I've taken
another sweep through this routine: we now work on just "arg", which
plays the same role as "check_arg" did before. We keep around
"orig_arg" for those cases where we really need the original argument
(before we saw through the TYPE_PACK_EXPANSION).

> > +          if ((TYPE_P (pattern) && same_type_p (pattern, parm_pack))
> > +              || (!TYPE_P (pattern) && cp_tree_equal (parm_pack, pattern)))
> > +            /* The argument pack that the parameter maps to is just an
> > +               expansion of the parameter itself, such as one would
> > +               find in the implicit typedef of a class inside the
> > +               class itself.  Consider this parameter "unsubstituted",
> > +               so that we will maintain the outer pack expansion.  */

It happens in the test for PR 31993, here:

  template<typename...> struct A;

  template<template<int> class... T> struct A<T<0>...>
  {
    template<int> struct B {};
    B<0> b;
  };

When we lookup 'B<0>' (in lookup_template_class), we find
A<T<0>...>::B<0>. In performing the substitution for the template
arguments of A<T<0>...>::B, we substitute both the outer level of
arguments and the inner level of arguments. In the outer level of
arguments, we end up substituting the expansion of 'T' for 'T'.
Normally, substituting into an expansion produces a new argument pack,
but not here: we want to retain the pack expansion because nothing is
actually being expanded.

> > +                /* We can get a pack expansion here when we are
> > +                   instantiating a member template and ARG is a pack
> > +                   expansion from the outer template.  */
> > +                if (PACK_EXPANSION_P (arg))
> > +                  arg = PACK_EXPANSION_PATTERN (arg);
>
> Can you give me an example of how these two situations come up?  It's
> not clear to me how the testcases relate to the fixes.

Ah, this case no longer happens here, because we've dealt with it in
tsubst_pack_expansion above. I've removed this cruft.

Here's an updated patch. Tested i686-pc-linux-gnu, no regressions. It
fixes the two PRs mentioned in the original e-mail (32252 and 31993).

  - Doug

2007-10-26  Douglas Gregor  <doug.gregor@gmail.com>

	PR c++/31993
	PR c++/32252
	* pt.c (find_parameter_packs_r): Fix typo in comment.
	(convert_template_argument): Look at the pattern of a pack
	expansion to determine what kind of entity we're converting.
	(coerce_template_parameter_pack): When we have coerced a non-type
	template parameter pack, substitute into the type of that pack.
	(tsubst_pack_expansion): When our substitution of a parameter pack
	is a "trivial" substitution of itself, just substitute into the
	pack expansion rather than actually expanding.

2007-10-26  Douglas Gregor  <doug.gregor@gmail.com>

	* g++.dg/cpp0x/pr31993.C: New
	* g++.dg/cpp0x/pr32252.C: New

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

Index: testsuite/g++.dg/cpp0x/pr31993.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr31993.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr31993.C	(revision 0)
@@ -0,0 +1,9 @@
+// { dg-options "-std=c++0x" }
+
+template<typename...> struct A;
+
+template<template<int> class... T> struct A<T<0>...>
+{
+  template<int> struct B {};
+  B<0> b;
+};
Index: testsuite/g++.dg/cpp0x/pr32252.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr32252.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr32252.C	(revision 0)
@@ -0,0 +1,8 @@
+// { dg-options "-std=c++0x" }
+int x[5];
+
+template<int M, int N, int (&... p)[N]> struct A;
+
+template<int M> struct A<M,5,x> {};
+
+A<0,5,x> a;  
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 129655)
+++ cp/pt.c	(working copy)
@@ -2416,9 +2416,9 @@ struct find_parameter_pack_data 
   struct pointer_set_t *visited;
 };
 
-/* Identifiers all of the argument packs that occur in a template
+/* Identifies all of the argument packs that occur in a template
    argument and appends them to the TREE_LIST inside DATA, which is a
-   find_parameter_pack_Data structure. This is a subroutine of
+   find_parameter_pack_data structure. This is a subroutine of
    make_pack_expansion and uses_parameter_packs.  */
 static tree
 find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
@@ -4657,9 +4657,9 @@ convert_template_argument (tree parm,
 			   int i,
 			   tree in_decl)
 {
+  tree orig_arg;
   tree val;
   int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
-  tree check_arg = arg;
 
   if (TREE_CODE (arg) == TREE_LIST
       && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
@@ -4669,24 +4669,26 @@ convert_template_argument (tree parm,
 	 invalid, but static members are OK.  In any
 	 case, grab the underlying fields/functions
 	 and issue an error later if required.  */
-      arg = TREE_VALUE (arg);
+      orig_arg = TREE_VALUE (arg);
       TREE_TYPE (arg) = unknown_type_node;
     }
 
+  orig_arg = arg;
+
   requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
   requires_type = (TREE_CODE (parm) == TYPE_DECL
 		   || requires_tmpl_type);
 
   /* When determining whether an argument pack expansion is a template,
      look at the pattern.  */
-  if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
-    check_arg = PACK_EXPANSION_PATTERN (check_arg);
+  if (TREE_CODE (arg) == TYPE_PACK_EXPANSION)
+    arg = PACK_EXPANSION_PATTERN (arg);
 
   is_tmpl_type = 
-    ((TREE_CODE (check_arg) == TEMPLATE_DECL
-      && TREE_CODE (DECL_TEMPLATE_RESULT (check_arg)) == TYPE_DECL)
-     || TREE_CODE (check_arg) == TEMPLATE_TEMPLATE_PARM
-     || TREE_CODE (check_arg) == UNBOUND_CLASS_TEMPLATE);
+    ((TREE_CODE (arg) == TEMPLATE_DECL
+      && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
+     || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
+     || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
 
   if (is_tmpl_type
       && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
@@ -4699,12 +4701,13 @@ convert_template_argument (tree parm,
       && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
     {
       pedwarn ("to refer to a type member of a template parameter, "
-	       "use %<typename %E%>", arg);
+	       "use %<typename %E%>", orig_arg);
 
-      arg = make_typename_type (TREE_OPERAND (arg, 0),
-				TREE_OPERAND (arg, 1),
-				typename_type,
-				complain & tf_error);
+      orig_arg = make_typename_type (TREE_OPERAND (arg, 0),
+				     TREE_OPERAND (arg, 1),
+				     typename_type,
+				     complain & tf_error);
+      arg = orig_arg;
       is_type = 1;
     }
   if (is_type != requires_type)
@@ -4719,11 +4722,11 @@ convert_template_argument (tree parm,
 	      if (is_type)
 		error ("  expected a constant of type %qT, got %qT",
 		       TREE_TYPE (parm),
-		       (is_tmpl_type ? DECL_NAME (arg) : arg));
+		       (is_tmpl_type ? DECL_NAME (arg) : orig_arg));
 	      else if (requires_tmpl_type)
-		error ("  expected a class template, got %qE", arg);
+		error ("  expected a class template, got %qE", orig_arg);
 	      else
-		error ("  expected a type, got %qE", arg);
+		error ("  expected a type, got %qE", orig_arg);
 	    }
 	}
       return error_mark_node;
@@ -4738,7 +4741,7 @@ convert_template_argument (tree parm,
 	  if (is_tmpl_type)
 	    error ("  expected a type, got %qT", DECL_NAME (arg));
 	  else
-	    error ("  expected a class template, got %qT", arg);
+	    error ("  expected a class template, got %qT", orig_arg);
 	}
       return error_mark_node;
     }
@@ -4756,19 +4759,13 @@ convert_template_argument (tree parm,
 	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
 	      tree argparm;
 
-              check_arg = arg;
-              /* When determining whether a pack expansion is a template,
-                 look at the pattern.  */
-              if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
-                check_arg = PACK_EXPANSION_PATTERN (check_arg);
-
-              argparm = DECL_INNERMOST_TEMPLATE_PARMS (check_arg);
+              argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
 
 	      if (coerce_template_template_parms (parmparm, argparm,
 						  complain, in_decl,
 						  args))
 		{
-		  val = arg;
+		  val = orig_arg;
 
 		  /* TEMPLATE_TEMPLATE_PARM node is preferred over
 		     TEMPLATE_DECL.  */
@@ -4777,9 +4774,9 @@ convert_template_argument (tree parm,
                       if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
                         val = TREE_TYPE (val);
                       else if (TREE_CODE (val) == TYPE_PACK_EXPANSION
-                               && DECL_TEMPLATE_TEMPLATE_PARM_P (check_arg))
+                               && DECL_TEMPLATE_TEMPLATE_PARM_P (arg))
                         {
-                          val = TREE_TYPE (check_arg);
+                          val = TREE_TYPE (arg);
                           val = make_pack_expansion (val);
                         }
                     }
@@ -4792,7 +4789,7 @@ convert_template_argument (tree parm,
 			     "template parameter list for %qD",
 			     i + 1, in_decl);
 		      error ("  expected a template of type %qD, got %qD",
-			     parm, arg);
+			     parm, orig_arg);
 		    }
 
 		  val = error_mark_node;
@@ -4800,7 +4797,7 @@ convert_template_argument (tree parm,
 	    }
 	}
       else
-	val = arg;
+	val = orig_arg;
       /* We only form one instance of each template specialization.
 	 Therefore, if we use a non-canonical variant (i.e., a
 	 typedef), any future messages referring to the type will use
@@ -4816,7 +4813,7 @@ convert_template_argument (tree parm,
       if (invalid_nontype_parm_type_p (t, complain))
 	return error_mark_node;
 
-      if (!uses_template_parms (arg) && !uses_template_parms (t))
+      if (!uses_template_parms (orig_arg) && !uses_template_parms (t))
 	/* We used to call digest_init here.  However, digest_init
 	   will report errors, which we don't want when complain
 	   is zero.  More importantly, digest_init will try too
@@ -4827,14 +4824,14 @@ convert_template_argument (tree parm,
 	   conversions can occur is part of determining which
 	   function template to call, or whether a given explicit
 	   argument specification is valid.  */
-	val = convert_nontype_argument (t, arg);
+	val = convert_nontype_argument (t, orig_arg);
       else
-	val = arg;
+	val = orig_arg;
 
       if (val == NULL_TREE)
 	val = error_mark_node;
       else if (val == error_mark_node && (complain & tf_error))
-	error ("could not convert template argument %qE to %qT",  arg, t);
+	error ("could not convert template argument %qE to %qT",  orig_arg, t);
     }
 
   return val;
@@ -4948,7 +4945,8 @@ coerce_template_parameter_pack (tree par
   else
     {
       argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
-      TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+      TREE_TYPE (argument_pack) 
+        = tsubst (TREE_TYPE (TREE_VALUE (parm)), args, complain, in_decl);
       TREE_CONSTANT (argument_pack) = 1;
     }
 
@@ -7097,6 +7095,22 @@ tsubst_pack_expansion (tree t, tree args
 	  return result;
 	}
 
+      if (arg_pack
+          && TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
+          && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
+        {
+          tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
+          tree pattern = PACK_EXPANSION_PATTERN (expansion);
+          if ((TYPE_P (pattern) && same_type_p (pattern, parm_pack))
+              || (!TYPE_P (pattern) && cp_tree_equal (parm_pack, pattern)))
+            /* The argument pack that the parameter maps to is just an
+               expansion of the parameter itself, such as one would
+               find in the implicit typedef of a class inside the
+               class itself.  Consider this parameter "unsubstituted",
+               so that we will maintain the outer pack expansion.  */
+            arg_pack = NULL_TREE;
+        }
+          
       if (arg_pack)
         {
           int my_len = 

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

* Re: PING: C++0x variadic templates fixes
  2007-10-26 18:24   ` Doug Gregor
@ 2007-10-30  7:12     ` Jason Merrill
  0 siblings, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2007-10-30  7:12 UTC (permalink / raw)
  To: Doug Gregor; +Cc: GCC Patches

OK.

Jason

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

end of thread, other threads:[~2007-10-30  4:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-25 19:40 PING: C++0x variadic templates fixes Doug Gregor
2007-08-17 19:29 ` Jason Merrill
2007-08-31 19:42   ` Doug Gregor
2007-10-26 18:24   ` Doug Gregor
2007-10-30  7:12     ` Jason Merrill

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).